Compare commits
879
Commits
spreader_only
...
list
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edae3c9ab7 | ||
|
|
fd9892c6b6 | ||
|
|
45668baaf8 | ||
|
|
305cc0e01c | ||
|
|
f0f365538b | ||
|
|
f9bba0baed | ||
|
|
306c18065a | ||
|
|
c64c71c98c | ||
|
|
7de87c1c25 | ||
|
|
12716bb6e1 | ||
|
|
8e68d573ff | ||
|
|
dd66e94bfd | ||
|
|
d399f75648 | ||
|
|
937173dd2f | ||
|
|
f1f7a40fba | ||
|
|
5522d364d4 | ||
|
|
3a218d246e | ||
|
|
bafc28e3bc | ||
|
|
6d1eb474c4 | ||
|
|
d172f4ffab | ||
|
|
c527b6e84f | ||
|
|
b8c7abd6b3 | ||
|
|
fea8e184c1 | ||
|
|
44a7bc0de9 | ||
|
|
4bad9ef183 | ||
|
|
590835c627 | ||
|
|
997766df92 | ||
|
|
cdbf66cd6c | ||
|
|
4c90eed59e | ||
|
|
d260f8ce2c | ||
|
|
12d0afb215 | ||
|
|
a9040f5f8f | ||
|
|
6e6acb5a71 | ||
|
|
256697d5b0 | ||
|
|
be9067b22e | ||
|
|
a5874a59f0 | ||
|
|
e8405e5638 | ||
|
|
ab70c9dfb1 | ||
|
|
1e4d8584c7 | ||
|
|
29eef77099 | ||
|
|
c50e89ae78 | ||
|
|
89917713d6 | ||
|
|
1e0ac46e07 | ||
|
|
6279b8f5f5 | ||
|
|
4007c87e20 | ||
|
|
ec0f42e76c | ||
|
|
99f63c2a6f | ||
|
|
12ac20f756 | ||
|
|
9d36d74005 | ||
|
|
da2cc977a0 | ||
|
|
84e7bdb586 | ||
|
|
b062a229c8 | ||
|
|
8680b3d815 | ||
|
|
6ab0e4c5a7 | ||
|
|
867bcf97d0 | ||
|
|
360bf9b37e | ||
|
|
4d85106fbf | ||
|
|
64a253b581 | ||
|
|
5f379c1356 | ||
|
|
76c80383ce | ||
|
|
e5a6ea80f0 | ||
|
|
b921e644df | ||
|
|
1c3fb8c192 | ||
|
|
d530d86a30 | ||
|
|
9d9229ef56 | ||
|
|
6f6f3c0800 | ||
|
|
7b234044f6 | ||
|
|
d46c82f34c | ||
|
|
4d5af610f0 | ||
|
|
1e94466f24 | ||
|
|
3210c0bce4 | ||
|
|
849f4ac579 | ||
|
|
6d56f67697 | ||
|
|
c0289719e7 | ||
|
|
a32e969b39 | ||
|
|
f5899e7781 | ||
|
|
ed07c956a7 | ||
|
|
2022ee5a07 | ||
|
|
a0bc1e8691 | ||
|
|
c1951ac49a | ||
|
|
e159e0e77b | ||
|
|
6bbd4134ec | ||
|
|
8a72b2150a | ||
|
|
e4d5d1eeb2 | ||
|
|
6bf2726b63 | ||
|
|
a63af0cb46 | ||
|
|
b2a7e1d2ed | ||
|
|
32a38b3b5a | ||
|
|
8533bcf0a7 | ||
|
|
e00eae1129 | ||
|
|
95595c4cbf | ||
|
|
aad36a4972 | ||
|
|
cc03f47d70 | ||
|
|
5c5e5c23ef | ||
|
|
4b531a2a1a | ||
|
|
35530bec0b | ||
|
|
5853bb2436 | ||
|
|
bfdf45d30d | ||
|
|
a330bc5020 | ||
|
|
66f68ef3ec | ||
|
|
d6e651129b | ||
|
|
d4a59b8253 | ||
|
|
569f1460a4 | ||
|
|
2f369dbd57 | ||
|
|
444e486862 | ||
|
|
b42504d827 | ||
|
|
18ac85a454 | ||
|
|
788a1a06c5 | ||
|
|
787b485bce | ||
|
|
788df0e888 | ||
|
|
916532f7c5 | ||
|
|
3c511bb177 | ||
|
|
49f13755c6 | ||
|
|
dcb4b1ae7e | ||
|
|
2152b48fe2 | ||
|
|
b6f2f99f21 | ||
|
|
c44df8ec06 | ||
|
|
493f082d6d | ||
|
|
bbe76b2709 | ||
|
|
ce8eda24fc | ||
|
|
9f9113bf9a | ||
|
|
a199595938 | ||
|
|
83de5fac75 | ||
|
|
c688657d53 | ||
|
|
a5c62c66b1 | ||
|
|
6d595d18ee | ||
|
|
946e8f1c47 | ||
|
|
b765c3756d | ||
|
|
54dc7bf6c3 | ||
|
|
6142a08db6 | ||
|
|
ca59976e00 | ||
|
|
7f7a160916 | ||
|
|
c8eb51c303 | ||
|
|
4160233a58 | ||
|
|
c5f79f754b | ||
|
|
5f568d681a | ||
|
|
83a2147428 | ||
|
|
9dd2cee6d9 | ||
|
|
57365013bd | ||
|
|
3d55ef075b | ||
|
|
14da6461b1 | ||
|
|
e84d3df024 | ||
|
|
ed38fe0ce9 | ||
|
|
b5daee3bcf | ||
|
|
f5c8c29f5a | ||
|
|
89fa2eae50 | ||
|
|
41b8c9238c | ||
|
|
28b66306da | ||
|
|
0bdbc1897a | ||
|
|
c3d9443a89 | ||
|
|
400db13a78 | ||
|
|
1d7d5858d5 | ||
|
|
8792f24c5d | ||
|
|
76d35b16eb | ||
|
|
81f7fe72ab | ||
|
|
649ba11edb | ||
|
|
2fc6d7c262 | ||
|
|
45421eedce | ||
|
|
8ecb3118e4 | ||
|
|
3fdb10890d | ||
|
|
2a6224c88d | ||
|
|
8d6ddc8250 | ||
|
|
6cc8590a1c | ||
|
|
063d908775 | ||
|
|
93565f0ebf | ||
|
|
1d7fcf5d18 | ||
|
|
897d20f12f | ||
|
|
a928925252 | ||
|
|
4088affa15 | ||
|
|
7def6aacd2 | ||
|
|
94ae1780cd | ||
|
|
2c65c4376b | ||
|
|
68bb3dbfa1 | ||
|
|
82a73693a6 | ||
|
|
612cd4a4c8 | ||
|
|
b3828dfc53 | ||
|
|
01f26567ed | ||
|
|
90d21c9c15 | ||
|
|
6351c1340e | ||
|
|
18cdddf76d | ||
|
|
b14c8bb1ac | ||
|
|
ceff286120 | ||
|
|
59aa4677e8 | ||
|
|
996cd4c856 | ||
|
|
9287149c26 | ||
|
|
306b56a999 | ||
|
|
812cf0a43f | ||
|
|
2c539fd833 | ||
|
|
334295ed67 | ||
|
|
c157b9cdfd | ||
|
|
8280b7a815 | ||
|
|
fb7f982c65 | ||
|
|
75b50d93e8 | ||
|
|
865bdac9df | ||
|
|
ebe5f468d7 | ||
|
|
1bc8d886f4 | ||
|
|
38e352e0d3 | ||
|
|
f6079e7031 | ||
|
|
8c51488190 | ||
|
|
9aad08ada6 | ||
|
|
2d3d11ba59 | ||
|
|
6087953185 | ||
|
|
851654c8a5 | ||
|
|
57a4745e29 | ||
|
|
32cd00895e | ||
|
|
dee5f2684f | ||
|
|
f639a526cf | ||
|
|
d168d8712e | ||
|
|
78a9605383 | ||
|
|
a713b1018e | ||
|
|
9f626dd10c | ||
|
|
8ec7fdd60a | ||
|
|
ffb2245ae6 | ||
|
|
21051c9a0b | ||
|
|
1c8bd34144 | ||
|
|
f614fb7e7d | ||
|
|
b222cd3e55 | ||
|
|
4f2be64813 | ||
|
|
bfb73ffc5a | ||
|
|
9bb7025752 | ||
|
|
bbfbd0b691 | ||
|
|
5628e96a90 | ||
|
|
ef517b7554 | ||
|
|
ba06af327d | ||
|
|
b8b03172bc | ||
|
|
fb5c3c1e6e | ||
|
|
faaa7b11d4 | ||
|
|
92a0467e1e | ||
|
|
3bb2025ea2 | ||
|
|
f2730ff0d7 | ||
|
|
7fcff9e5b4 | ||
|
|
51f83f4880 | ||
|
|
88cb510aea | ||
|
|
452c642af0 | ||
|
|
3fafc5004e | ||
|
|
fd8e502140 | ||
|
|
b499a5c38b | ||
|
|
2320383b16 | ||
|
|
59b3e73330 | ||
|
|
9d9a1b86c4 | ||
|
|
21cc2cefbf | ||
|
|
904df4260d | ||
|
|
af785d5d0b | ||
|
|
1d796856ca | ||
|
|
35f0d5a53f | ||
|
|
2b2fdd2b94 | ||
|
|
9e4539a902 | ||
|
|
a76c8ffd98 | ||
|
|
d7474cb8da | ||
|
|
890a23a537 | ||
|
|
ab17eee260 | ||
|
|
acadc3bd7c | ||
|
|
8701fb7132 | ||
|
|
89fcb3092b | ||
|
|
c9856b96ae | ||
|
|
04477a4b7c | ||
|
|
99371a2ead | ||
|
|
70487a8ef7 | ||
|
|
44c419fdaf | ||
|
|
5eb151f9a0 | ||
|
|
855a939c51 | ||
|
|
7071d9b961 | ||
|
|
adf14491bc | ||
|
|
7e0e8f2801 | ||
|
|
4a37e2d6a6 | ||
|
|
12b2371a69 | ||
|
|
c19d173983 | ||
|
|
203164f372 | ||
|
|
6f69f1c2e2 | ||
|
|
ad1a585b5c | ||
|
|
f29e367ec7 | ||
|
|
18127383f0 | ||
|
|
b450c757c9 | ||
|
|
836683bcbe | ||
|
|
c271af30d8 | ||
|
|
31fab94208 | ||
|
|
a9b5067d7a | ||
|
|
7a31b025a2 | ||
|
|
31897a1b2e | ||
|
|
f93bc592cb | ||
|
|
6ca2753951 | ||
|
|
470ca0093e | ||
|
|
7e1715964f | ||
|
|
39e929a614 | ||
|
|
a9aa06f275 | ||
|
|
54510c9e59 | ||
|
|
cb56429f04 | ||
|
|
ac8147cc0f | ||
|
|
82ac189ac9 | ||
|
|
5721ff78b6 | ||
|
|
7afd2947f1 | ||
|
|
c3e3862c5f | ||
|
|
bf2dc9ecca | ||
|
|
e0e188a02c | ||
|
|
79ba1654d3 | ||
|
|
2aab0d18a5 | ||
|
|
312c8ded11 | ||
|
|
3f86779da6 | ||
|
|
716d3b8482 | ||
|
|
24f6dbc4f0 | ||
|
|
3e943fa35e | ||
|
|
457f878b41 | ||
|
|
ac2b2d042a | ||
|
|
829d2cdbf6 | ||
|
|
3cd9693b36 | ||
|
|
2b52ecf2ef | ||
|
|
faab60cbc1 | ||
|
|
b6be0d649d | ||
|
|
2a65c45d21 | ||
|
|
dc6ae2ac29 | ||
|
|
df4250c33a | ||
|
|
53504ef6f0 | ||
|
|
10afb1af06 | ||
|
|
a9149dfa87 | ||
|
|
5afa6695e7 | ||
|
|
d2a6d54090 | ||
|
|
794ac25c01 | ||
|
|
37214e9480 | ||
|
|
90ab551778 | ||
|
|
9a4ec46440 | ||
|
|
c86d283755 | ||
|
|
941956c1b5 | ||
|
|
67e3d22104 | ||
|
|
7e41c93f9a | ||
|
|
086ccbb3fa | ||
|
|
329ddc576d | ||
|
|
1faef425ab | ||
|
|
bb068cf6b2 | ||
|
|
f7cade41c6 | ||
|
|
47afd3a911 | ||
|
|
ef80d2a41d | ||
|
|
44ef080e9f | ||
|
|
fef8d2c413 | ||
|
|
201746e561 | ||
|
|
8e375a0b7f | ||
|
|
045f3dc060 | ||
|
|
6b6012236d | ||
|
|
9cee798939 | ||
|
|
c79bdb12e0 | ||
|
|
bce77d65de | ||
|
|
0db814ef2d | ||
|
|
31b5ec4bd3 | ||
|
|
e15cdfd76e | ||
|
|
eb150ba82c | ||
|
|
d763275179 | ||
|
|
2b96a8a5c4 | ||
|
|
31866c76b7 | ||
|
|
a2da946e03 | ||
|
|
528bab34e7 | ||
|
|
776b9e4f94 | ||
|
|
168d328e97 | ||
|
|
f871dbd230 | ||
|
|
1662b56ea0 | ||
|
|
f3302dbac0 | ||
|
|
181072f3e7 | ||
|
|
f654312123 | ||
|
|
c46d97646a | ||
|
|
41742359e9 | ||
|
|
024723925e | ||
|
|
76b834768e | ||
|
|
89284bea87 | ||
|
|
532154640b | ||
|
|
ab8468d498 | ||
|
|
84b0332778 | ||
|
|
20b601f290 | ||
|
|
47002cae4c | ||
|
|
eaaffe369a | ||
|
|
7292a31c00 | ||
|
|
389d762a93 | ||
|
|
9704ebf096 | ||
|
|
de320338ca | ||
|
|
668dfd9130 | ||
|
|
a2960b23a8 | ||
|
|
55744edc25 | ||
|
|
7ece5d18cb | ||
|
|
8005ac8635 | ||
|
|
c00a71fdfa | ||
|
|
197c915968 | ||
|
|
6d77a07bbe | ||
|
|
adfb560dd1 | ||
|
|
508d20e4e0 | ||
|
|
72457619f7 | ||
|
|
18d5b83a95 | ||
|
|
653362b947 | ||
|
|
b7477b8f93 | ||
|
|
105f1fceaf | ||
|
|
cb65489ab7 | ||
|
|
96772727df | ||
|
|
960a618fe1 | ||
|
|
505cd37225 | ||
|
|
a5f66b8ac6 | ||
|
|
2021f29f62 | ||
|
|
9ccf3e0f87 | ||
|
|
7cfc53eba8 | ||
|
|
f9d269c750 | ||
|
|
67d5161fd1 | ||
|
|
d6e9bbce71 | ||
|
|
76ec2c0fa2 | ||
|
|
e82a2c9402 | ||
|
|
60ce106e24 | ||
|
|
1eb4952422 | ||
|
|
3043582889 | ||
|
|
f604db6517 | ||
|
|
f95b0c19d7 | ||
|
|
655bf87e92 | ||
|
|
6d06a1920d | ||
|
|
70af51e163 | ||
|
|
2c17fe334e | ||
|
|
5eca2cd3ac | ||
|
|
4b5ff8cad4 | ||
|
|
89d5b25cc7 | ||
|
|
3e10d403b4 | ||
|
|
1ebf06d49a | ||
|
|
2be857a851 | ||
|
|
1de22a82e8 | ||
|
|
f275308cc8 | ||
|
|
79de0dd4d8 | ||
|
|
5cedf74406 | ||
|
|
e5de6b4ad7 | ||
|
|
e467195de1 | ||
|
|
913a5b4a7e | ||
|
|
feb8bd9b79 | ||
|
|
846ecfa776 | ||
|
|
d98fb399a8 | ||
|
|
4a1c1d023a | ||
|
|
43cba548f4 | ||
|
|
772910ffe5 | ||
|
|
767179caf7 | ||
|
|
ee4a9150b8 | ||
|
|
58914fa703 | ||
|
|
ba40e7044a | ||
|
|
010d0073fe | ||
|
|
40210ce42e | ||
|
|
59cdafba21 | ||
|
|
fe6226baa5 | ||
|
|
45987c7652 | ||
|
|
a18ce97fb4 | ||
|
|
13d5080bbc | ||
|
|
9f07a36d1d | ||
|
|
bc2e7f428a | ||
|
|
53bfbdd349 | ||
|
|
174eac9a59 | ||
|
|
3775b86d9e | ||
|
|
5e1c6d6209 | ||
|
|
0d0fb036ab | ||
|
|
f8668802ab | ||
|
|
c22a1382a1 | ||
|
|
941a0d91cc | ||
|
|
60456e4225 | ||
|
|
440e28489a | ||
|
|
3da0f4eedc | ||
|
|
497abfb443 | ||
|
|
7b04a7849b | ||
|
|
e14b1e0b07 | ||
|
|
2121ce2841 | ||
|
|
c22e99941e | ||
|
|
3da646dc8a | ||
|
|
fca675d43f | ||
|
|
a30523744d | ||
|
|
80f5117c34 | ||
|
|
f77f73ec36 | ||
|
|
2385cf0d1b | ||
|
|
bc778ad5bb | ||
|
|
acb9c35d3b | ||
|
|
b8473e2632 | ||
|
|
61b4696574 | ||
|
|
91a79a5d96 | ||
|
|
23927edf46 | ||
|
|
6c03e605b8 | ||
|
|
2e201159d8 | ||
|
|
5d56a8e440 | ||
|
|
7097c85555 | ||
|
|
bf4c8e252f | ||
|
|
866cf33cd4 | ||
|
|
4561560b46 | ||
|
|
bbadbf8e16 | ||
|
|
68d8659115 | ||
|
|
dd008962a7 | ||
|
|
e856e7e58f | ||
|
|
634d8e1aeb | ||
|
|
eaa9376577 | ||
|
|
3fb70fd645 | ||
|
|
b793c75aa8 | ||
|
|
cb26b9af39 | ||
|
|
f8059cc87e | ||
|
|
07fe19ecdc | ||
|
|
a292fe87e1 | ||
|
|
03d915b55c | ||
|
|
cc318535e9 | ||
|
|
9d245f3243 | ||
|
|
6d7f95ac8e | ||
|
|
9d9df76f4e | ||
|
|
a850082f44 | ||
|
|
521150a73b | ||
|
|
ed5f3fe740 | ||
|
|
fd6fdd9768 | ||
|
|
73bf104e9f | ||
|
|
24640e65b1 | ||
|
|
eadfc38a69 | ||
|
|
098ee36c3a | ||
|
|
f4ed4d38f1 | ||
|
|
2ed3eaa325 | ||
|
|
3a7a02244b | ||
|
|
79258b9404 | ||
|
|
6376802d04 | ||
|
|
2784e7652d | ||
|
|
5b3925fae0 | ||
|
|
077f6050f3 | ||
|
|
791dd62b67 | ||
|
|
2364cda362 | ||
|
|
aca4365e8d | ||
|
|
cac857a3a7 | ||
|
|
ed38ce958d | ||
|
|
ed4b9b7426 | ||
|
|
e4468f056d | ||
|
|
4b580b407e | ||
|
|
b575612b07 | ||
|
|
b506b971a4 | ||
|
|
c50f322dc1 | ||
|
|
3a61f4d81d | ||
|
|
a2b2de9783 | ||
|
|
b2a6927b4b | ||
|
|
80dec4e1e2 | ||
|
|
77c7802496 | ||
|
|
cec2687085 | ||
|
|
ac118993d5 | ||
|
|
7634ecf730 | ||
|
|
309d1fa287 | ||
|
|
9231a91fb4 | ||
|
|
f6f928a693 | ||
|
|
467216439b | ||
|
|
c63e73ab7c | ||
|
|
74fcacd800 | ||
|
|
c1c46f01ab | ||
|
|
77083a1fa6 | ||
|
|
5303f290b1 | ||
|
|
895871c94b | ||
|
|
3bff50b764 | ||
|
|
86b7802b3b | ||
|
|
4ff9aaf037 | ||
|
|
99f7827e7e | ||
|
|
b67ac5c849 | ||
|
|
0777f01607 | ||
|
|
222dbf5443 | ||
|
|
9434f61030 | ||
|
|
9199594756 | ||
|
|
fc9318a831 | ||
|
|
e3fc28f082 | ||
|
|
9cb7b84f57 | ||
|
|
2689ed806d | ||
|
|
5999e7856f | ||
|
|
96ad67b020 | ||
|
|
47d5b95e13 | ||
|
|
12108e6046 | ||
|
|
021bdb8c23 | ||
|
|
470f6c0988 | ||
|
|
c8b87b4f79 | ||
|
|
9d7e16fbf7 | ||
|
|
5a45d5e12a | ||
|
|
c793ec78a2 | ||
|
|
7b2b7c5854 | ||
|
|
327615c9ac | ||
|
|
8e5d94b5e7 | ||
|
|
bd76a1f260 | ||
|
|
1df2695f50 | ||
|
|
67d33a3315 | ||
|
|
c49cd3a06e | ||
|
|
6c0545f566 | ||
|
|
f0eee365f9 | ||
|
|
274db506a9 | ||
|
|
1e5c56f3a7 | ||
|
|
871c7a131f | ||
|
|
7642d73f39 | ||
|
|
ef69dfa646 | ||
|
|
377be5030f | ||
|
|
896af55e79 | ||
|
|
b9a4a2c148 | ||
|
|
e9f6d096cf | ||
|
|
25d4c54284 | ||
|
|
e4291e1c51 | ||
|
|
5c11708728 | ||
|
|
73a301192f | ||
|
|
d972564d34 | ||
|
|
e66a2d4663 | ||
|
|
f92e13d898 | ||
|
|
3d0698b326 | ||
|
|
1e0ab86a24 | ||
|
|
caa29b9513 | ||
|
|
c793768918 | ||
|
|
0132a0cff6 | ||
|
|
f83b6ee898 | ||
|
|
dc071dfa56 | ||
|
|
fbfd601270 | ||
|
|
9b5aea2458 | ||
|
|
904ef92ece | ||
|
|
74e950d459 | ||
|
|
e99caef2dc | ||
|
|
855e4a6ed8 | ||
|
|
311b956461 | ||
|
|
b3b308cd9d | ||
|
|
a8480a34ba | ||
|
|
3312637b8d | ||
|
|
e6f7a82fb1 | ||
|
|
5b934de69a | ||
|
|
0f78982f57 | ||
|
|
18abbfc502 | ||
|
|
c3ae4c6dc5 | ||
|
|
9b012649cd | ||
|
|
c126091155 | ||
|
|
c2fee56496 | ||
|
|
5461dc77aa | ||
|
|
1b2a1c3fe3 | ||
|
|
a83a4fdd4f | ||
|
|
4d4ee1f57c | ||
|
|
2bec4ae09f | ||
|
|
e3b91909a6 | ||
|
|
116ba3f629 | ||
|
|
0ce6f8e6a2 | ||
|
|
9447cb67d2 | ||
|
|
92dacc5c3c | ||
|
|
766dfe9dd3 | ||
|
|
84ecb54efd | ||
|
|
6ff8855dba | ||
|
|
7f349cfa71 | ||
|
|
948b23addc | ||
|
|
7031bb6fbe | ||
|
|
15a04a1870 | ||
|
|
741c6d360a | ||
|
|
c4f3ca26ef | ||
|
|
3403adc1ff | ||
|
|
410d3aaf20 | ||
|
|
34905f6053 | ||
|
|
6a16d419af | ||
|
|
cd23c1a5a1 | ||
|
|
18793f8cd9 | ||
|
|
c008147674 | ||
|
|
47323c51c3 | ||
|
|
91f58620ac | ||
|
|
91aeccb2ae | ||
|
|
82864a609d | ||
|
|
828b1ca0c2 | ||
|
|
6b740ece39 | ||
|
|
84f18288e0 | ||
|
|
cf9e5862ed | ||
|
|
4ca2b5f4d2 | ||
|
|
da2894512d | ||
|
|
55e9487203 | ||
|
|
19fb08e7ff | ||
|
|
193b1025ad | ||
|
|
8fa2a925cd | ||
|
|
526daa9647 | ||
|
|
43bcc9fe02 | ||
|
|
51d6066420 | ||
|
|
0b11b83eb5 | ||
|
|
a53dfd14b1 | ||
|
|
cc0380d8f1 | ||
|
|
0a01d22e72 | ||
|
|
e9f1c72198 | ||
|
|
14af8823ed | ||
|
|
5900ce7d12 | ||
|
|
33e0a6bb46 | ||
|
|
ca3bc5059e | ||
|
|
bd108dfe35 | ||
|
|
8a96c7441e | ||
|
|
4eea3194fd | ||
|
|
dace332ac5 | ||
|
|
af816bb905 | ||
|
|
195c24ffef | ||
|
|
92ad17aa19 | ||
|
|
eabc4bee4c | ||
|
|
0ed9142cf0 | ||
|
|
1639683b43 | ||
|
|
05afb08c5d | ||
|
|
c674e44c60 | ||
|
|
e104c78471 | ||
|
|
3d8ec63bd7 | ||
|
|
99670c9d28 | ||
|
|
56126e19a7 | ||
|
|
05e8363504 | ||
|
|
884741062b | ||
|
|
63c77966fa | ||
|
|
31745d9f0d | ||
|
|
78897ed608 | ||
|
|
5712bcdc57 | ||
|
|
8e0a027584 | ||
|
|
12f88b5303 | ||
|
|
b119cad8a9 | ||
|
|
f30210e4e1 | ||
|
|
a8d6a104c3 | ||
|
|
13df0c8638 | ||
|
|
fb70aa6514 | ||
|
|
37fd1d424e | ||
|
|
bdbbcb05dc | ||
|
|
9cd5d0890f | ||
|
|
7b1fa849ef | ||
|
|
a8b5cf81ee | ||
|
|
bc62d4b359 | ||
|
|
4413580212 | ||
|
|
8b653ef133 | ||
|
|
b1f8ac7e22 | ||
|
|
a11c23d718 | ||
|
|
9feceb9fdb | ||
|
|
bad6464fe9 | ||
|
|
a6007ca362 | ||
|
|
05348b01ae | ||
|
|
abfabe3e21 | ||
|
|
83e0da446a | ||
|
|
85a48e71d1 | ||
|
|
0671117660 | ||
|
|
654c5b3074 | ||
|
|
aee5e54c14 | ||
|
|
e5df037992 | ||
|
|
06b9586eb6 | ||
|
|
79716dfdba | ||
|
|
02b6b5d078 | ||
|
|
403e8d2947 | ||
|
|
25e9c37987 | ||
|
|
99b58cf2bf | ||
|
|
78155cfbdf | ||
|
|
1ba980d69f | ||
|
|
ef155aaedf | ||
|
|
22c4b528cb | ||
|
|
fd71c6ac7a | ||
|
|
019fa134cb | ||
|
|
4a40bd3364 | ||
|
|
68229b2474 | ||
|
|
8727ed6ccd | ||
|
|
8ee3d5b8ad | ||
|
|
98ee43aa27 | ||
|
|
92291e3f9f | ||
|
|
1abb41a0d5 | ||
|
|
0993195f03 | ||
|
|
c2a7c6f994 | ||
|
|
48900cf5a0 | ||
|
|
57fbb36808 | ||
|
|
5c45384c34 | ||
|
|
f9aa162e2a | ||
|
|
013d17c386 | ||
|
|
ad250c3883 | ||
|
|
2c9e0012e2 | ||
|
|
2516f23e37 | ||
|
|
d3a7bd48c2 | ||
|
|
4aeb7490e3 | ||
|
|
265beef715 | ||
|
|
a58bf83a9a | ||
|
|
9da1a4a2de | ||
|
|
8a98e38e73 | ||
|
|
3044f4a0b1 | ||
|
|
5104ae1742 | ||
|
|
987ec14da2 | ||
|
|
24c6e0df97 | ||
|
|
23d5d18b28 | ||
|
|
0a38c241af | ||
|
|
5b0d79ad17 | ||
|
|
833187559d | ||
|
|
527066e4c8 | ||
|
|
bad30a49bf | ||
|
|
24f40dd652 | ||
|
|
dce61183dd | ||
|
|
aeb81a9e86 | ||
|
|
81aea15988 | ||
|
|
3e393208ab | ||
|
|
0674accd05 | ||
|
|
0f0d8df572 | ||
|
|
0afd06be9c | ||
|
|
1539bfa8b1 | ||
|
|
a2336be143 | ||
|
|
7d65befc7e | ||
|
|
916b28bc16 | ||
|
|
fb3447a6b4 | ||
|
|
2fa9b2e0e5 | ||
|
|
a66d3fb28a | ||
|
|
6be017d35b | ||
|
|
ef24e5164f | ||
|
|
a7f36b2361 | ||
|
|
3d404002a0 | ||
|
|
1922a1b49c | ||
|
|
ca4ec7025c | ||
|
|
7dcfa709d5 | ||
|
|
aa254142e8 | ||
|
|
b00b12bed2 | ||
|
|
dd7168a687 | ||
|
|
97b665733a | ||
|
|
4a6d3e3042 | ||
|
|
f65cf43e21 | ||
|
|
f971d4db51 | ||
|
|
8cd79c0372 | ||
|
|
9bc346e84a | ||
|
|
88d2e1756f | ||
|
|
dc09c45330 | ||
|
|
47e5b57789 | ||
|
|
c1ad8ed4b2 | ||
|
|
3589b5c9a8 | ||
|
|
fbaf15ad34 | ||
|
|
ee1d02991c | ||
|
|
2450cb028e | ||
|
|
ec1182f059 | ||
|
|
7797d8255f | ||
|
|
a4780ecac7 | ||
|
|
32643990ee | ||
|
|
5746e6267a | ||
|
|
501ec81405 | ||
|
|
714f4fe995 | ||
|
|
ead71a5618 | ||
|
|
eaf6e4ba28 | ||
|
|
bef2c9310e | ||
|
|
7b3e0d4a59 | ||
|
|
ea0705e7e4 | ||
|
|
7b9310f595 | ||
|
|
a31f775de8 | ||
|
|
f061630789 | ||
|
|
5d442125b0 | ||
|
|
e600f444f8 | ||
|
|
a8ae4d6655 | ||
|
|
a885fa7065 | ||
|
|
65665dc384 | ||
|
|
a8992edf88 | ||
|
|
1b7dd28c2f | ||
|
|
ae692432a2 | ||
|
|
c779b31a90 | ||
|
|
cb4bf8f5f4 | ||
|
|
96cd807720 | ||
|
|
07c3150d2a | ||
|
|
c66a405e6d | ||
|
|
0558381bcb | ||
|
|
1db47684b7 | ||
|
|
e16abd2e8b | ||
|
|
f7adc84f0e | ||
|
|
3acd51b247 | ||
|
|
6caab9c017 | ||
|
|
97c61d2a4f | ||
|
|
4f6a0061fe | ||
|
|
5b201069e8 | ||
|
|
8b5d79847f | ||
|
|
2d112a86af | ||
|
|
8806a62af7 | ||
|
|
01748ee847 | ||
|
|
6f1fb24a31 | ||
|
|
c30459115e | ||
|
|
7cdfcbf6dc | ||
|
|
acf140e670 | ||
|
|
df4a18e887 | ||
|
|
dc3836065a | ||
|
|
3df7ab194c | ||
|
|
c0af8460a2 | ||
|
|
85d94a84a8 | ||
|
|
6ad6a361f9 | ||
|
|
2a5dcab60f | ||
|
|
02b97d594f | ||
|
|
5e1cac251b | ||
|
|
3639638bf2 | ||
|
|
e255e054d4 | ||
|
|
8c9d8e7089 | ||
|
|
f0e069d348 | ||
|
|
4f32c8469e | ||
|
|
b2679ecb60 | ||
|
|
e0537267a2 | ||
|
|
3440afd0d6 | ||
|
|
cab65a0aaf | ||
|
|
910908b43e | ||
|
|
cf1c1e6df1 | ||
|
|
ff9b4f5b2f | ||
|
|
01899428e3 | ||
|
|
ff75ade140 | ||
|
|
25d5f36645 | ||
|
|
5c5f042cac | ||
|
|
7da0b32838 | ||
|
|
389896be07 | ||
|
|
f55323afca | ||
|
|
0d5313d263 | ||
|
|
bc676b9731 | ||
|
|
0313a90196 | ||
|
|
fca1c62a55 | ||
|
|
2dcb0d6177 | ||
|
|
e2eea4bca7 | ||
|
|
9218184ef1 | ||
|
|
a9ec9e87be | ||
|
|
258d4a3fc1 | ||
|
|
c53f6425cd |
No files matched your search
+3
-3
@@ -1,5 +1,6 @@
|
||||
nohup.out
|
||||
build/
|
||||
build/**
|
||||
install/**
|
||||
.build_proxy/
|
||||
cmake-build-debug/
|
||||
.cache/
|
||||
@@ -40,8 +41,6 @@ trace_data/
|
||||
.ionide/*
|
||||
/.ignore
|
||||
*.rej
|
||||
/build
|
||||
/build.*/*
|
||||
.clangd/
|
||||
*CMakeDeps.cmake
|
||||
/sniper.ipynb
|
||||
@@ -51,3 +50,4 @@ trace_data/
|
||||
*.tmp/*
|
||||
/.venv*/*
|
||||
.cache/
|
||||
src/web/api/tsconfig.*.g.json
|
||||
@@ -7,6 +7,3 @@
|
||||
[submodule "docker/windows"]
|
||||
path = docker/windows
|
||||
url = git@bitbucket.org:bluetradesys/windows_docker.git
|
||||
[submodule "src/deribit-crypto-connector-demo-application"]
|
||||
path = src/deribit-crypto-connector-demo-application
|
||||
url = git@gitlab.com:cryptoexchanges1/deribit-crypto-connector-demo-application.git
|
||||
+22
-3
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project(spark)
|
||||
|
||||
if(WIN32)
|
||||
@@ -7,12 +7,18 @@ else()
|
||||
set(platform "linux")
|
||||
endif()
|
||||
|
||||
set(EXTERNALS_ROOT "${CMAKE_SOURCE_DIR}/externals/${platform}")
|
||||
set(
|
||||
EXTERNALS_ROOT
|
||||
"${CMAKE_SOURCE_DIR}/externals/${platform}"
|
||||
CACHE
|
||||
STRING
|
||||
"External dependencies root folder (should contain folders: lib, bin, include")
|
||||
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")
|
||||
set(BUILD_WEB ON CACHE BOOL "Build the web server")
|
||||
|
||||
include_directories(BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
|
||||
link_directories(${SPARK_LIB})
|
||||
@@ -47,6 +53,12 @@ else()
|
||||
# make sparkd look for libspark.so in its directory
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
set(CMAKE_INSTALL_RPATH ".")
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install/${CMAKE_BUILD_TYPE}/sparkd")
|
||||
add_compile_definitions(SPARK_ENABLE_CCAPI)
|
||||
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_FTX)
|
||||
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE)
|
||||
add_compile_definitions(CCAPI_ENABLE_LOG_WARN)
|
||||
|
||||
# flags
|
||||
set(
|
||||
@@ -67,7 +79,9 @@ else()
|
||||
# subdirs
|
||||
add_subdirectory(src/server/sparkd)
|
||||
add_subdirectory(src/lib)
|
||||
add_subdirectory(src/web)
|
||||
if (BUILD_WEB)
|
||||
add_subdirectory(src/web)
|
||||
endif()
|
||||
add_subdirectory(doc/user)
|
||||
if(BUILD_SDK)
|
||||
add_subdirectory(src/sdk)
|
||||
@@ -91,4 +105,9 @@ else()
|
||||
DEPENDS sparkd data_files_dir)
|
||||
|
||||
add_custom_target(server_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/server)
|
||||
|
||||
install(DIRECTORY "${CMAKE_BINARY_DIR}/server/plugins" DESTINATION bin)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libACE-5.7.5.so" DESTINATION bin)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0" DESTINATION bin)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/externals/src/emumba/sparkd.lic" DESTINATION bin)
|
||||
endif()
|
||||
@@ -106,8 +106,9 @@ function(Service_Compiler_Generate_Cpp SRCS HDRS)
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.client.pb.h"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.server.pb.cc"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.server.pb.h"
|
||||
COMMAND
|
||||
"PYTHONPATH=${SPARK_PYTHON}" ${Protobuf_PROTOC_EXECUTABLE} ARGS
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/tools/venv_exec.sh
|
||||
ARGS
|
||||
${Protobuf_PROTOC_EXECUTABLE}
|
||||
--cpp_out=${CMAKE_BINARY_DIR}/src
|
||||
--plugin=protoc-gen-service=${CMAKE_SOURCE_DIR}/src/lib/api/service_compiler/plugin.py
|
||||
--service_out=lang=cpp,make_file_name=${ABS_FIL}:${CMAKE_BINARY_DIR}/src
|
||||
File renamed without changes.
@@ -46,6 +46,7 @@ function setup_build
|
||||
assert_dir $repo_root
|
||||
assert_dir $build_root
|
||||
set compiler "$argv[1]"
|
||||
set c_compiler (which cc)
|
||||
set build_type "$argv[2]"
|
||||
|
||||
if test \( -z "$build_type" \) -o \( \( "$build_type" != debug \) -a \( "$build_type" != release \) \)
|
||||
@@ -59,6 +60,7 @@ function setup_build
|
||||
else
|
||||
# set compiler_arg "/usr/lib/ccache/clang++"
|
||||
set compiler_arg "clang++"
|
||||
set c_compiler (which clang)
|
||||
end
|
||||
else if test "$build_type" = release
|
||||
set build_type_arg Release
|
||||
@@ -85,7 +87,7 @@ function setup_build
|
||||
rm -rf "$build_dest"
|
||||
mkdir -p "$build_dest"
|
||||
cd "$build_dest"
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=$build_type_arg -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_CXX_COMPILER=$compiler_arg $repo_root
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=$build_type_arg -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_C_COMPILER=$c_compiler -DCMAKE_CXX_COMPILER=$compiler_arg $repo_root
|
||||
end
|
||||
|
||||
# The while loop below removes arguments (via shift) as it parses them.
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,941 @@
|
||||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"type": "dark",
|
||||
"colors": {
|
||||
"activityBar.background": "#111111",
|
||||
"activityBar.border": "#111111",
|
||||
"activityBar.foreground": "#888888",
|
||||
"activityBarBadge.background": "#88cc44",
|
||||
"activityBarBadge.foreground": "#222222",
|
||||
"badge.background": "#88cc44",
|
||||
"badge.foreground": "#222222",
|
||||
"button.background": "#333333",
|
||||
"button.foreground": "#888888",
|
||||
"button.hoverBackground": "#222222",
|
||||
"debugExceptionWidget.background": "#333333",
|
||||
"debugExceptionWidget.border": "#222222",
|
||||
"debugToolBar.background": "#111111",
|
||||
"diffEditor.insertedTextBackground": "#ffdd440c",
|
||||
"diffEditor.insertedTextBorder": "#ffdd44",
|
||||
"diffEditor.removedTextBackground": "#88bbff0c",
|
||||
"diffEditor.removedTextBorder": "#88bbff",
|
||||
"dropdown.background": "#222222",
|
||||
"dropdown.border": "#222222",
|
||||
"dropdown.foreground": "#888888",
|
||||
"editor.background": "#222222",
|
||||
"editor.findMatchBackground": "#44446655",
|
||||
"editor.findMatchHighlightBackground": "#444466aa",
|
||||
"editor.foreground": "#ffffff",
|
||||
"editor.hoverHighlightBackground": "#44446655",
|
||||
"editor.inactiveSelectionBackground": "#44446655",
|
||||
"editor.lineHighlightBackground": "#00000066",
|
||||
"editor.lineHighlightBorder": "#00000000",
|
||||
"editor.rangeHighlightBackground": "#333333",
|
||||
"editor.selectionBackground": "#444466",
|
||||
"editor.selectionHighlightBackground": "#44446655",
|
||||
"editor.wordHighlightBackground": "#44446655",
|
||||
"editor.wordHighlightStrongBackground": "#44446655",
|
||||
"editorBracketMatch.background": "#222222",
|
||||
"editorBracketMatch.border": "#666666",
|
||||
"editorCodeLens.foreground": "#666666",
|
||||
"editorCursor.foreground": "#ffffff",
|
||||
"editorError.foreground": "#ee5500",
|
||||
"editorGroup.border": "#111111",
|
||||
"editorGroup.dropBackground": "#111111bb",
|
||||
"editorGroupHeader.noTabsBackground": "#111111",
|
||||
"editorGroupHeader.tabsBackground": "#111111",
|
||||
"editorGroupHeader.tabsBorder": "#222222",
|
||||
"editorGutter.addedBackground": "#ffdd44",
|
||||
"editorGutter.background": "#222222",
|
||||
"editorGutter.deletedBackground": "#88bbff",
|
||||
"editorGutter.modifiedBackground": "#88bbff",
|
||||
"editorHoverWidget.background": "#333333",
|
||||
"editorHoverWidget.border": "#222222",
|
||||
"editorIndentGuide.background": "#333333",
|
||||
"editorLineNumber.foreground": "#555555",
|
||||
"editorLink.activeForeground": "#bba0ff",
|
||||
"editorMarkerNavigation.background": "#333333",
|
||||
"editorMarkerNavigationError.background": "#88bbff",
|
||||
"editorMarkerNavigationWarning.background": "#88bbff",
|
||||
"editorOverviewRuler.addedForeground": "#ffdd44",
|
||||
"editorOverviewRuler.border": "#222222",
|
||||
"editorOverviewRuler.currentContentForeground": "#333333",
|
||||
"editorOverviewRuler.deletedForeground": "#88bbff",
|
||||
"editorOverviewRuler.errorForeground": "#88bbff",
|
||||
"editorOverviewRuler.findMatchForeground": "#555555",
|
||||
"editorOverviewRuler.incomingContentForeground": "#333333",
|
||||
"editorOverviewRuler.infoForeground": "#bba0ff",
|
||||
"editorOverviewRuler.modifiedForeground": "#88bbff",
|
||||
"editorOverviewRuler.rangeHighlightForeground": "#333333",
|
||||
"editorOverviewRuler.selectionHighlightForeground": "#555555",
|
||||
"editorOverviewRuler.warningForeground": "#88bbff",
|
||||
"editorOverviewRuler.wordHighlightForeground": "#333333",
|
||||
"editorOverviewRuler.wordHighlightStrongForeground": "#555555",
|
||||
"editorRuler.foreground": "#ffffff",
|
||||
"editorSuggestWidget.background": "#333333",
|
||||
"editorSuggestWidget.border": "#333333",
|
||||
"editorSuggestWidget.foreground": "#888888",
|
||||
"editorSuggestWidget.highlightForeground": "#ffffff",
|
||||
"editorSuggestWidget.selectedBackground": "#666666",
|
||||
"editorWarning.border": "#00000000",
|
||||
"editorWarning.foreground": "#88bbff",
|
||||
"editorWhitespace.foreground": "#333333",
|
||||
"editorWidget.background": "#333333",
|
||||
"editorWidget.border": "#333333",
|
||||
"errorForeground": "#88bbff",
|
||||
"extensionButton.prominentBackground": "#333333",
|
||||
"extensionButton.prominentForeground": "#ffffff",
|
||||
"extensionButton.prominentHoverBackground": "#555555",
|
||||
"focusBorder": "#666666",
|
||||
"foreground": "#ffffff",
|
||||
"gitDecoration.modifiedResourceForeground": "#cccccc",
|
||||
"gitDecoration.untrackedResourceForeground": "#cccccc",
|
||||
"input.background": "#333333",
|
||||
"input.border": "#333333",
|
||||
"input.foreground": "#ffffff",
|
||||
"input.placeholderForeground": "#555555",
|
||||
"inputOption.activeBorder": "#555555",
|
||||
"inputValidation.errorBackground": "#333333",
|
||||
"inputValidation.errorBorder": "#88bbff",
|
||||
"inputValidation.infoBackground": "#333333",
|
||||
"inputValidation.infoBorder": "#bba0ff",
|
||||
"inputValidation.warningBackground": "#333333",
|
||||
"inputValidation.warningBorder": "#88bbff",
|
||||
"list.activeSelectionBackground": "#111111",
|
||||
"list.activeSelectionForeground": "#ffffff",
|
||||
"list.dropBackground": "#111111bf",
|
||||
"list.focusBackground": "#222222",
|
||||
"list.focusForeground": "#ffffff",
|
||||
"list.highlightForeground": "#ffffff",
|
||||
"list.hoverBackground": "#333333",
|
||||
"list.hoverForeground": "#ffffff",
|
||||
"list.inactiveSelectionBackground": "#000000",
|
||||
"list.inactiveSelectionForeground": "#ffffff",
|
||||
"menu.background": "#333333",
|
||||
"menu.foreground": "#ffffff",
|
||||
"merge.border": "#222222",
|
||||
"merge.currentContentBackground": "#333333",
|
||||
"merge.currentHeaderBackground": "#555555",
|
||||
"merge.incomingContentBackground": "#555555",
|
||||
"merge.incomingHeaderBackground": "#666666",
|
||||
"panel.background": "#111111",
|
||||
"panel.border": "#111111",
|
||||
"panelTitle.activeBorder": "#ffffff",
|
||||
"panelTitle.activeForeground": "#ffffff",
|
||||
"panelTitle.inactiveForeground": "#888888",
|
||||
"peekView.border": "#222222",
|
||||
"peekViewEditor.background": "#333333",
|
||||
"peekViewEditor.matchHighlightBackground": "#555555",
|
||||
"peekViewEditorGutter.background": "#333333",
|
||||
"peekViewResult.background": "#333333",
|
||||
"peekViewResult.fileForeground": "#888888",
|
||||
"peekViewResult.lineForeground": "#888888",
|
||||
"peekViewResult.matchHighlightBackground": "#555555",
|
||||
"peekViewResult.selectionBackground": "#333333",
|
||||
"peekViewResult.selectionForeground": "#ffffff",
|
||||
"peekViewTitle.background": "#333333",
|
||||
"peekViewTitleDescription.foreground": "#888888",
|
||||
"peekViewTitleLabel.foreground": "#ffffff",
|
||||
"pickerGroup.border": "#222222",
|
||||
"pickerGroup.foreground": "#555555",
|
||||
"progressBar.background": "#333333",
|
||||
"scrollbar.shadow": "#191919",
|
||||
"scrollbarSlider.activeBackground": "#ffffff12",
|
||||
"scrollbarSlider.background": "#ffffff12",
|
||||
"scrollbarSlider.hoverBackground": "#ffffff12",
|
||||
"selection.background": "#2255aa",
|
||||
"sideBar.background": "#111111",
|
||||
"sideBar.border": "#111111",
|
||||
"sideBar.foreground": "#888888",
|
||||
"sideBarSectionHeader.background": "#111111",
|
||||
"sideBarSectionHeader.foreground": "#666666",
|
||||
"sideBarTitle.foreground": "#555555",
|
||||
"statusBar.background": "#111111",
|
||||
"statusBar.border": "#111111",
|
||||
"statusBar.debuggingBackground": "#666666",
|
||||
"statusBar.debuggingForeground": "#ffffff",
|
||||
"statusBar.foreground": "#666666",
|
||||
"statusBar.noFolderBackground": "#111111",
|
||||
"statusBar.noFolderForeground": "#666666",
|
||||
"statusBarItem.activeBackground": "#222222",
|
||||
"statusBarItem.hoverBackground": "#222222",
|
||||
"statusBarItem.prominentBackground": "#333333",
|
||||
"statusBarItem.prominentHoverBackground": "#444444",
|
||||
"tab.activeBackground": "#222222",
|
||||
"tab.border": "#111111",
|
||||
"tab.inactiveBackground": "#111111",
|
||||
"tab.inactiveForeground": "#888888",
|
||||
"tab.unfocusedActiveBorder": "#888888",
|
||||
"tab.unfocusedActiveForeground": "#888888",
|
||||
"tab.unfocusedInactiveForeground": "#888888",
|
||||
"terminal.ansiBlack": "#333333",
|
||||
"terminal.ansiBlue": "#88bbff",
|
||||
"terminal.ansiBrightBlack": "#666666",
|
||||
"terminal.ansiBrightBlue": "#88bbff",
|
||||
"terminal.ansiBrightCyan": "#bba0ff",
|
||||
"terminal.ansiBrightGreen": "#ffdd44",
|
||||
"terminal.ansiBrightMagenta": "#88bbff",
|
||||
"terminal.ansiBrightRed": "#88bbff",
|
||||
"terminal.ansiBrightWhite": "#ffffff",
|
||||
"terminal.ansiBrightYellow": "#88cc44",
|
||||
"terminal.ansiCyan": "#bba0ff",
|
||||
"terminal.ansiGreen": "#ffdd44",
|
||||
"terminal.ansiMagenta": "#88bbff",
|
||||
"terminal.ansiRed": "#88bbff",
|
||||
"terminal.ansiWhite": "#ffffff",
|
||||
"terminal.ansiYellow": "#88cc44",
|
||||
"terminal.background": "#151515",
|
||||
"terminal.foreground": "#ffffff",
|
||||
"titleBar.activeBackground": "#111111",
|
||||
"titleBar.activeForeground": "#888888",
|
||||
"titleBar.inactiveBackground": "#111111",
|
||||
"titleBar.inactiveForeground": "#555555",
|
||||
"walkThrough.embeddedEditorBackground": "#111111",
|
||||
"widget.shadow": "#111111",
|
||||
//"activityBar.activeBorder": "#888888",
|
||||
//"activityBar.dropBorder": "#888888",
|
||||
//"activityBar.inactiveForeground": "#88888866",
|
||||
//"banner.background": "#111111",
|
||||
//"banner.foreground": "#ffffff",
|
||||
//"banner.iconForeground": "#3794ff",
|
||||
//"bookmarks.lineBackground": "#00000000",
|
||||
//"bookmarks.lineBorder": "#00000000",
|
||||
//"bookmarks.overviewRuler": "#157efb88",
|
||||
//"breadcrumb.activeSelectionForeground": "#ffffff",
|
||||
//"breadcrumb.background": "#222222",
|
||||
//"breadcrumb.focusForeground": "#ffffff",
|
||||
//"breadcrumb.foreground": "#ffffffcc",
|
||||
//"breadcrumbPicker.background": "#333333",
|
||||
//"button.secondaryBackground": "#3a3d41",
|
||||
//"button.secondaryForeground": "#ffffff",
|
||||
//"button.secondaryHoverBackground": "#45494e",
|
||||
//"charts.blue": "#3794ff",
|
||||
//"charts.foreground": "#ffffff",
|
||||
//"charts.green": "#89d185",
|
||||
//"charts.lines": "#ffffff80",
|
||||
//"charts.orange": "#d18616",
|
||||
//"charts.purple": "#b180d7",
|
||||
//"charts.red": "#ee5500",
|
||||
//"charts.yellow": "#88bbff",
|
||||
//"checkbox.background": "#222222",
|
||||
//"checkbox.border": "#222222",
|
||||
//"checkbox.foreground": "#888888",
|
||||
//"debugConsole.errorForeground": "#88bbff",
|
||||
//"debugConsole.infoForeground": "#3794ff",
|
||||
//"debugConsole.sourceForeground": "#ffffff",
|
||||
//"debugConsole.warningForeground": "#88bbff",
|
||||
//"debugConsoleInputIcon.foreground": "#ffffff",
|
||||
//"debugIcon.breakpointCurrentStackframeForeground": "#ffcc00",
|
||||
//"debugIcon.breakpointDisabledForeground": "#848484",
|
||||
//"debugIcon.breakpointForeground": "#e51400",
|
||||
//"debugIcon.breakpointStackframeForeground": "#89d185",
|
||||
//"debugIcon.breakpointUnverifiedForeground": "#848484",
|
||||
//"debugIcon.continueForeground": "#75beff",
|
||||
//"debugIcon.disconnectForeground": "#f48771",
|
||||
//"debugIcon.pauseForeground": "#75beff",
|
||||
//"debugIcon.restartForeground": "#89d185",
|
||||
//"debugIcon.startForeground": "#89d185",
|
||||
//"debugIcon.stepBackForeground": "#75beff",
|
||||
//"debugIcon.stepIntoForeground": "#75beff",
|
||||
//"debugIcon.stepOutForeground": "#75beff",
|
||||
//"debugIcon.stepOverForeground": "#75beff",
|
||||
//"debugIcon.stopForeground": "#f48771",
|
||||
//"debugTokenExpression.boolean": "#4e94ce",
|
||||
//"debugTokenExpression.error": "#f48771",
|
||||
//"debugTokenExpression.name": "#c586c0",
|
||||
//"debugTokenExpression.number": "#b5cea8",
|
||||
//"debugTokenExpression.string": "#ce9178",
|
||||
//"debugTokenExpression.value": "#cccccc99",
|
||||
//"debugView.exceptionLabelBackground": "#6c2022",
|
||||
//"debugView.exceptionLabelForeground": "#ffffff",
|
||||
//"debugView.stateLabelBackground": "#88888844",
|
||||
//"debugView.stateLabelForeground": "#ffffff",
|
||||
//"debugView.valueChangedHighlight": "#569cd6",
|
||||
//"descriptionForeground": "#ffffffb3",
|
||||
//"diffEditor.diagonalFill": "#cccccc33",
|
||||
//"editor.findRangeHighlightBackground": "#3a3d4166",
|
||||
//"editor.focusedStackFrameHighlightBackground": "#7abd7a4d",
|
||||
//"editor.foldBackground": "#4444664d",
|
||||
//"editor.inlineValuesBackground": "#ffc80033",
|
||||
//"editor.inlineValuesForeground": "#ffffff80",
|
||||
//"editor.linkedEditingBackground": "#ff00004d",
|
||||
//"editor.snippetFinalTabstopHighlightBorder": "#525252",
|
||||
//"editor.snippetTabstopHighlightBackground": "#7c7c7c4d",
|
||||
//"editor.stackFrameHighlightBackground": "#ffff0033",
|
||||
//"editor.symbolHighlightBackground": "#444466aa",
|
||||
//"editorActiveLineNumber.foreground": "#c6c6c6",
|
||||
//"editorBracketHighlight.foreground1": "#ffd700",
|
||||
//"editorBracketHighlight.foreground2": "#da70d6",
|
||||
//"editorBracketHighlight.foreground3": "#179fff",
|
||||
//"editorBracketHighlight.foreground4": "#00000000",
|
||||
//"editorBracketHighlight.foreground5": "#00000000",
|
||||
//"editorBracketHighlight.foreground6": "#00000000",
|
||||
//"editorBracketHighlight.unexpectedBracket.foreground": "#ff1212cc",
|
||||
//"editorBracketPairGuide.activeBackground1": "#00000000",
|
||||
//"editorBracketPairGuide.activeBackground2": "#00000000",
|
||||
//"editorBracketPairGuide.activeBackground3": "#00000000",
|
||||
//"editorBracketPairGuide.activeBackground4": "#00000000",
|
||||
//"editorBracketPairGuide.activeBackground5": "#00000000",
|
||||
//"editorBracketPairGuide.activeBackground6": "#00000000",
|
||||
//"editorBracketPairGuide.background1": "#00000000",
|
||||
//"editorBracketPairGuide.background2": "#00000000",
|
||||
//"editorBracketPairGuide.background3": "#00000000",
|
||||
//"editorBracketPairGuide.background4": "#00000000",
|
||||
//"editorBracketPairGuide.background5": "#00000000",
|
||||
//"editorBracketPairGuide.background6": "#00000000",
|
||||
//"editorGhostText.foreground": "#ffffff56",
|
||||
//"editorGutter.commentRangeForeground": "#c5c5c5",
|
||||
//"editorGutter.foldingControlForeground": "#c5c5c5",
|
||||
//"editorHint.foreground": "#eeeeeeb3",
|
||||
//"editorHoverWidget.foreground": "#ffffff",
|
||||
//"editorHoverWidget.highlightForeground": "#ffffff",
|
||||
//"editorHoverWidget.statusBarBackground": "#3d3d3d",
|
||||
//"editorIndentGuide.activeBackground": "#333333",
|
||||
//"editorInfo.foreground": "#3794ff",
|
||||
//"editorInlayHint.background": "#88cc4499",
|
||||
//"editorInlayHint.foreground": "#222222cc",
|
||||
//"editorInlayHint.parameterBackground": "#88cc4499",
|
||||
//"editorInlayHint.parameterForeground": "#222222cc",
|
||||
//"editorInlayHint.typeBackground": "#88cc4499",
|
||||
//"editorInlayHint.typeForeground": "#222222cc",
|
||||
//"editorLightBulb.foreground": "#ffcc00",
|
||||
//"editorLightBulbAutoFix.foreground": "#75beff",
|
||||
//"editorLineNumber.activeForeground": "#c6c6c6",
|
||||
//"editorMarkerNavigationError.headerBackground": "#88bbff1a",
|
||||
//"editorMarkerNavigationInfo.background": "#3794ff",
|
||||
//"editorMarkerNavigationInfo.headerBackground": "#3794ff1a",
|
||||
//"editorMarkerNavigationWarning.headerBackground": "#88bbff1a",
|
||||
//"editorOverviewRuler.bracketMatchForeground": "#a0a0a0",
|
||||
//"editorOverviewRuler.commonContentForeground": "#60606066",
|
||||
//"editorOverviewRuler.unicodeForeground": "#d186167e",
|
||||
//"editorPane.background": "#222222",
|
||||
//"editorSuggestWidget.focusHighlightForeground": "#ffffff",
|
||||
//"editorSuggestWidget.selectedForeground": "#ffffff",
|
||||
//"editorSuggestWidgetStatus.foreground": "#88888880",
|
||||
//"editorUnicodeHighlight.border": "#bd9b03",
|
||||
//"editorUnnecessaryCode.opacity": "#000000aa",
|
||||
//"editorWidget.foreground": "#ffffff",
|
||||
//"extensionBadge.remoteBackground": "#88cc44",
|
||||
//"extensionBadge.remoteForeground": "#222222",
|
||||
//"extensionIcon.preReleaseForeground": "#1d9271",
|
||||
//"extensionIcon.starForeground": "#ff8e00",
|
||||
//"extensionIcon.verifiedForeground": "#3794ff",
|
||||
//"gitDecoration.addedResourceForeground": "#81b88b",
|
||||
//"gitDecoration.conflictingResourceForeground": "#e4676b",
|
||||
//"gitDecoration.deletedResourceForeground": "#c74e39",
|
||||
//"gitDecoration.ignoredResourceForeground": "#8c8c8c",
|
||||
//"gitDecoration.renamedResourceForeground": "#73c991",
|
||||
//"gitDecoration.stageDeletedResourceForeground": "#c74e39",
|
||||
//"gitDecoration.stageModifiedResourceForeground": "#e2c08d",
|
||||
//"gitDecoration.submoduleResourceForeground": "#8db9e2",
|
||||
//"gitlens.closedAutolinkedIssueIconColor": "#a371f7",
|
||||
//"gitlens.closedPullRequestIconColor": "#f85149",
|
||||
//"gitlens.decorations.addedForegroundColor": "#81b88b",
|
||||
//"gitlens.decorations.branchAheadForegroundColor": "#35b15e",
|
||||
//"gitlens.decorations.branchBehindForegroundColor": "#b15e35",
|
||||
//"gitlens.decorations.branchDivergedForegroundColor": "#d8af1b",
|
||||
//"gitlens.decorations.branchMissingUpstreamForegroundColor": "#c74e39",
|
||||
//"gitlens.decorations.branchUnpublishedForegroundColor": "#35b15e",
|
||||
//"gitlens.decorations.branchUpToDateForegroundColor": "#888888",
|
||||
//"gitlens.decorations.copiedForegroundColor": "#73c991",
|
||||
//"gitlens.decorations.deletedForegroundColor": "#c74e39",
|
||||
//"gitlens.decorations.ignoredForegroundColor": "#8c8c8c",
|
||||
//"gitlens.decorations.modifiedForegroundColor": "#cccccc",
|
||||
//"gitlens.decorations.renamedForegroundColor": "#73c991",
|
||||
//"gitlens.decorations.untrackedForegroundColor": "#cccccc",
|
||||
//"gitlens.gutterBackgroundColor": "#ffffff13",
|
||||
//"gitlens.gutterForegroundColor": "#bebebe",
|
||||
//"gitlens.gutterUncommittedForegroundColor": "#00bcf299",
|
||||
//"gitlens.lineHighlightBackgroundColor": "#00bcf233",
|
||||
//"gitlens.lineHighlightOverviewRulerColor": "#00bcf299",
|
||||
//"gitlens.mergedPullRequestIconColor": "#a371f7",
|
||||
//"gitlens.openAutolinkedIssueIconColor": "#3fb950",
|
||||
//"gitlens.openPullRequestIconColor": "#3fb950",
|
||||
//"gitlens.trailingLineBackgroundColor": "#00000000",
|
||||
//"gitlens.trailingLineForegroundColor": "#99999959",
|
||||
//"gitlens.unpublishedCommitIconColor": "#35b15e",
|
||||
//"gitlens.unpulledChangesIconColor": "#b15e35",
|
||||
//"gitlens.unpushlishedChangesIconColor": "#35b15e",
|
||||
//"icon.foreground": "#c5c5c5",
|
||||
//"inputOption.activeBackground": "#66666666",
|
||||
//"inputOption.activeForeground": "#ffffff",
|
||||
//"inputOption.hoverBackground": "#5a5d5e80",
|
||||
//"interactive.activeCodeBorder": "#222222",
|
||||
//"interactive.inactiveCodeBorder": "#000000",
|
||||
//"keybindingLabel.background": "#8080802b",
|
||||
//"keybindingLabel.border": "#33333399",
|
||||
//"keybindingLabel.bottomBorder": "#44444499",
|
||||
//"keybindingLabel.foreground": "#cccccc",
|
||||
//"keybindingTable.headerBackground": "#ffffff0a",
|
||||
//"keybindingTable.rowsBackground": "#ffffff0a",
|
||||
//"list.deemphasizedForeground": "#8c8c8c",
|
||||
//"list.errorForeground": "#f88070",
|
||||
//"list.filterMatchBackground": "#444466aa",
|
||||
//"list.focusHighlightForeground": "#ffffff",
|
||||
//"list.focusOutline": "#666666",
|
||||
//"list.invalidItemForeground": "#b89500",
|
||||
//"list.warningForeground": "#cca700",
|
||||
//"listFilterWidget.background": "#653723",
|
||||
//"listFilterWidget.noMatchesOutline": "#be1100",
|
||||
//"listFilterWidget.outline": "#00000000",
|
||||
//"menu.selectionBackground": "#111111",
|
||||
//"menu.selectionForeground": "#ffffff",
|
||||
//"menu.separatorBackground": "#bbbbbb",
|
||||
//"menubar.selectionBackground": "#ffffff1a",
|
||||
//"menubar.selectionForeground": "#888888",
|
||||
//"merge.commonContentBackground": "#60606029",
|
||||
//"merge.commonHeaderBackground": "#60606066",
|
||||
//"minimap.errorHighlight": "#ff1212b3",
|
||||
//"minimap.findMatchHighlight": "#d18616",
|
||||
//"minimap.foregroundOpacity": "#000000",
|
||||
//"minimap.selectionHighlight": "#264f78",
|
||||
//"minimap.selectionOccurrenceHighlight": "#676767",
|
||||
//"minimap.unicodeHighlight": "#d18616",
|
||||
//"minimap.warningHighlight": "#88bbff",
|
||||
//"minimapGutter.addedBackground": "#587c0c",
|
||||
//"minimapGutter.deletedBackground": "#94151b",
|
||||
//"minimapGutter.modifiedBackground": "#0c7d9d",
|
||||
//"minimapSlider.activeBackground": "#ffffff09",
|
||||
//"minimapSlider.background": "#ffffff09",
|
||||
//"minimapSlider.hoverBackground": "#ffffff09",
|
||||
//"notebook.cellBorderColor": "#000000",
|
||||
//"notebook.cellEditorBackground": "#111111",
|
||||
//"notebook.cellInsertionIndicator": "#666666",
|
||||
//"notebook.cellStatusBarItemHoverBackground": "#ffffff26",
|
||||
//"notebook.cellToolbarSeparator": "#80808059",
|
||||
//"notebook.focusedCellBorder": "#666666",
|
||||
//"notebook.focusedEditorBorder": "#666666",
|
||||
//"notebook.inactiveFocusedCellBorder": "#000000",
|
||||
//"notebook.selectedCellBackground": "#000000",
|
||||
//"notebook.selectedCellBorder": "#000000",
|
||||
//"notebook.symbolHighlightBackground": "#ffffff0b",
|
||||
//"notebookScrollbarSlider.activeBackground": "#ffffff12",
|
||||
//"notebookScrollbarSlider.background": "#ffffff12",
|
||||
//"notebookScrollbarSlider.hoverBackground": "#ffffff12",
|
||||
//"notebookStatusErrorIcon.foreground": "#88bbff",
|
||||
//"notebookStatusRunningIcon.foreground": "#ffffff",
|
||||
//"notebookStatusSuccessIcon.foreground": "#89d185",
|
||||
//"notificationCenterHeader.background": "#424242",
|
||||
//"notificationLink.foreground": "#3794ff",
|
||||
//"notifications.background": "#333333",
|
||||
//"notifications.border": "#424242",
|
||||
//"notifications.foreground": "#ffffff",
|
||||
//"notificationsErrorIcon.foreground": "#ee5500",
|
||||
//"notificationsInfoIcon.foreground": "#3794ff",
|
||||
//"notificationsWarningIcon.foreground": "#88bbff",
|
||||
//"panel.dropBorder": "#ffffff",
|
||||
//"panelSection.border": "#111111",
|
||||
//"panelSection.dropBackground": "#111111bb",
|
||||
//"panelSectionHeader.background": "#80808033",
|
||||
//"ports.iconRunningProcessForeground": "#88cc44",
|
||||
//"problemsErrorIcon.foreground": "#ee5500",
|
||||
//"problemsInfoIcon.foreground": "#3794ff",
|
||||
//"problemsWarningIcon.foreground": "#88bbff",
|
||||
//"quickInput.background": "#333333",
|
||||
//"quickInput.foreground": "#ffffff",
|
||||
//"quickInputList.focusBackground": "#111111",
|
||||
//"quickInputList.focusForeground": "#ffffff",
|
||||
//"quickInputTitle.background": "#ffffff1b",
|
||||
//"sash.hoverBorder": "#666666",
|
||||
//"scm.providerBorder": "#454545",
|
||||
//"searchEditor.findMatchBackground": "#44446670",
|
||||
//"searchEditor.textInputBorder": "#333333",
|
||||
//"settings.checkboxBackground": "#222222",
|
||||
//"settings.checkboxBorder": "#222222",
|
||||
//"settings.checkboxForeground": "#888888",
|
||||
//"settings.dropdownBackground": "#222222",
|
||||
//"settings.dropdownBorder": "#222222",
|
||||
//"settings.dropdownForeground": "#888888",
|
||||
//"settings.dropdownListBorder": "#333333",
|
||||
//"settings.focusedRowBackground": "#80808024",
|
||||
//"settings.focusedRowBorder": "#ffffff1f",
|
||||
//"settings.headerForeground": "#e7e7e7",
|
||||
//"settings.modifiedItemIndicator": "#0c7d9d",
|
||||
//"settings.numberInputBackground": "#333333",
|
||||
//"settings.numberInputBorder": "#333333",
|
||||
//"settings.numberInputForeground": "#ffffff",
|
||||
//"settings.rowHoverBackground": "#80808012",
|
||||
//"settings.textInputBackground": "#333333",
|
||||
//"settings.textInputBorder": "#333333",
|
||||
//"settings.textInputForeground": "#ffffff",
|
||||
//"sideBar.dropBackground": "#111111bb",
|
||||
//"sideBySideEditor.horizontalBorder": "#111111",
|
||||
//"sideBySideEditor.verticalBorder": "#111111",
|
||||
//"statusBar.debuggingBorder": "#111111",
|
||||
//"statusBar.noFolderBorder": "#111111",
|
||||
//"statusBarItem.compactHoverBackground": "#ffffff33",
|
||||
//"statusBarItem.errorBackground": "#0066eb",
|
||||
//"statusBarItem.errorForeground": "#ffffff",
|
||||
//"statusBarItem.prominentForeground": "#666666",
|
||||
//"statusBarItem.remoteBackground": "#88cc44",
|
||||
//"statusBarItem.remoteForeground": "#222222",
|
||||
//"statusBarItem.warningBackground": "#0066eb",
|
||||
//"statusBarItem.warningForeground": "#ffffff",
|
||||
//"symbolIcon.arrayForeground": "#ffffff",
|
||||
//"symbolIcon.booleanForeground": "#ffffff",
|
||||
//"symbolIcon.classForeground": "#ee9d28",
|
||||
//"symbolIcon.colorForeground": "#ffffff",
|
||||
//"symbolIcon.constantForeground": "#ffffff",
|
||||
//"symbolIcon.constructorForeground": "#b180d7",
|
||||
//"symbolIcon.enumeratorForeground": "#ee9d28",
|
||||
//"symbolIcon.enumeratorMemberForeground": "#75beff",
|
||||
//"symbolIcon.eventForeground": "#ee9d28",
|
||||
//"symbolIcon.fieldForeground": "#75beff",
|
||||
//"symbolIcon.fileForeground": "#ffffff",
|
||||
//"symbolIcon.folderForeground": "#ffffff",
|
||||
//"symbolIcon.functionForeground": "#b180d7",
|
||||
//"symbolIcon.interfaceForeground": "#75beff",
|
||||
//"symbolIcon.keyForeground": "#ffffff",
|
||||
//"symbolIcon.keywordForeground": "#ffffff",
|
||||
//"symbolIcon.methodForeground": "#b180d7",
|
||||
//"symbolIcon.moduleForeground": "#ffffff",
|
||||
//"symbolIcon.namespaceForeground": "#ffffff",
|
||||
//"symbolIcon.nullForeground": "#ffffff",
|
||||
//"symbolIcon.numberForeground": "#ffffff",
|
||||
//"symbolIcon.objectForeground": "#ffffff",
|
||||
//"symbolIcon.operatorForeground": "#ffffff",
|
||||
//"symbolIcon.packageForeground": "#ffffff",
|
||||
//"symbolIcon.propertyForeground": "#ffffff",
|
||||
//"symbolIcon.referenceForeground": "#ffffff",
|
||||
//"symbolIcon.snippetForeground": "#ffffff",
|
||||
//"symbolIcon.stringForeground": "#ffffff",
|
||||
//"symbolIcon.structForeground": "#ffffff",
|
||||
//"symbolIcon.textForeground": "#ffffff",
|
||||
//"symbolIcon.typeParameterForeground": "#ffffff",
|
||||
//"symbolIcon.unitForeground": "#ffffff",
|
||||
//"symbolIcon.variableForeground": "#75beff",
|
||||
//"tab.activeForeground": "#ffffff",
|
||||
//"tab.activeModifiedBorder": "#3399cc",
|
||||
//"tab.inactiveModifiedBorder": "#3399cc80",
|
||||
//"tab.lastPinnedBorder": "#585858",
|
||||
//"tab.unfocusedActiveBackground": "#222222",
|
||||
//"tab.unfocusedActiveModifiedBorder": "#3399cc80",
|
||||
//"tab.unfocusedInactiveBackground": "#111111",
|
||||
//"tab.unfocusedInactiveModifiedBorder": "#3399cc40",
|
||||
//"terminal.border": "#111111",
|
||||
//"terminal.dropBackground": "#111111bb",
|
||||
//"terminal.selectionBackground": "#ffffff40",
|
||||
//"testing.iconErrored": "#f14c4c",
|
||||
//"testing.iconFailed": "#f14c4c",
|
||||
//"testing.iconPassed": "#73c991",
|
||||
//"testing.iconQueued": "#cca700",
|
||||
//"testing.iconSkipped": "#848484",
|
||||
//"testing.iconUnset": "#848484",
|
||||
//"testing.message.error.decorationForeground": "#ee5500",
|
||||
//"testing.message.error.lineBackground": "#ff000033",
|
||||
//"testing.message.info.decorationForeground": "#ffffff80",
|
||||
//"testing.peekBorder": "#ee5500",
|
||||
//"testing.peekHeaderBackground": "#ee55001a",
|
||||
//"testing.runAction": "#73c991",
|
||||
//"textBlockQuote.background": "#7f7f7f1a",
|
||||
//"textBlockQuote.border": "#007acc80",
|
||||
//"textCodeBlock.background": "#0a0a0a66",
|
||||
//"textLink.activeForeground": "#3794ff",
|
||||
//"textLink.foreground": "#3794ff",
|
||||
//"textPreformat.foreground": "#d7ba7d",
|
||||
//"textSeparator.foreground": "#ffffff2e",
|
||||
//"toolbar.activeBackground": "#63666750",
|
||||
//"toolbar.hoverBackground": "#5a5d5e50",
|
||||
//"tree.indentGuidesStroke": "#585858",
|
||||
//"tree.tableColumnsBorder": "#cccccc20",
|
||||
//"tree.tableOddRowsBackground": "#ffffff0a",
|
||||
//"welcomePage.progress.background": "#333333",
|
||||
//"welcomePage.progress.foreground": "#3794ff",
|
||||
//"welcomePage.tileBackground": "#333333",
|
||||
//"welcomePage.tileHoverBackground": "#3d3d3d",
|
||||
//"welcomePage.tileShadow": "#111111",
|
||||
//"activityBar.activeBackground": null,
|
||||
//"activityBar.activeFocusBorder": null,
|
||||
//"button.border": null,
|
||||
//"contrastActiveBorder": null,
|
||||
//"contrastBorder": null,
|
||||
//"debugToolBar.border": null,
|
||||
//"diffEditor.border": null,
|
||||
//"dropdown.listBackground": null,
|
||||
//"editor.findMatchBorder": null,
|
||||
//"editor.findMatchHighlightBorder": null,
|
||||
//"editor.findRangeHighlightBorder": null,
|
||||
//"editor.rangeHighlightBorder": null,
|
||||
//"editor.selectionForeground": null,
|
||||
//"editor.selectionHighlightBorder": null,
|
||||
//"editor.snippetFinalTabstopHighlightBackground": null,
|
||||
//"editor.snippetTabstopHighlightBorder": null,
|
||||
//"editor.symbolHighlightBorder": null,
|
||||
//"editor.wordHighlightBorder": null,
|
||||
//"editor.wordHighlightStrongBorder": null,
|
||||
//"editorCursor.background": null,
|
||||
//"editorError.background": null,
|
||||
//"editorError.border": null,
|
||||
//"editorGhostText.background": null,
|
||||
//"editorGhostText.border": null,
|
||||
//"editorGroup.emptyBackground": null,
|
||||
//"editorGroup.focusedEmptyBorder": null,
|
||||
//"editorGroupHeader.border": null,
|
||||
//"editorHint.border": null,
|
||||
//"editorInfo.background": null,
|
||||
//"editorInfo.border": null,
|
||||
//"editorOverviewRuler.background": null,
|
||||
//"editorSuggestWidget.selectedIconForeground": null,
|
||||
//"editorUnnecessaryCode.border": null,
|
||||
//"editorWarning.background": null,
|
||||
//"editorWidget.resizeBorder": null,
|
||||
//"inputValidation.errorForeground": null,
|
||||
//"inputValidation.infoForeground": null,
|
||||
//"inputValidation.warningForeground": null,
|
||||
//"list.activeSelectionIconForeground": null,
|
||||
//"list.filterMatchBorder": null,
|
||||
//"list.inactiveFocusBackground": null,
|
||||
//"list.inactiveFocusOutline": null,
|
||||
//"list.inactiveSelectionIconForeground": null,
|
||||
//"menu.border": null,
|
||||
//"menu.selectionBorder": null,
|
||||
//"menubar.selectionBorder": null,
|
||||
//"minimap.background": null,
|
||||
//"notebook.cellHoverBackground": null,
|
||||
//"notebook.focusedCellBackground": null,
|
||||
//"notebook.inactiveSelectedCellBorder": null,
|
||||
//"notebook.outputContainerBackgroundColor": null,
|
||||
//"notebook.outputContainerBorderColor": null,
|
||||
//"notificationCenter.border": null,
|
||||
//"notificationCenterHeader.foreground": null,
|
||||
//"notificationToast.border": null,
|
||||
//"panelInput.border": null,
|
||||
//"panelSectionHeader.border": null,
|
||||
//"panelSectionHeader.foreground": null,
|
||||
//"peekViewEditor.matchHighlightBorder": null,
|
||||
//"quickInput.list.focusBackground": null,
|
||||
//"quickInputList.focusIconForeground": null,
|
||||
//"searchEditor.findMatchBorder": null,
|
||||
//"sideBarSectionHeader.border": null,
|
||||
//"tab.activeBorder": null,
|
||||
//"tab.activeBorderTop": null,
|
||||
//"tab.hoverBackground": null,
|
||||
//"tab.hoverBorder": null,
|
||||
//"tab.hoverForeground": null,
|
||||
//"tab.unfocusedActiveBorderTop": null,
|
||||
//"tab.unfocusedHoverBackground": null,
|
||||
//"tab.unfocusedHoverBorder": null,
|
||||
//"tab.unfocusedHoverForeground": null,
|
||||
//"terminal.tab.activeBorder": null,
|
||||
//"terminalCursor.background": null,
|
||||
//"terminalCursor.foreground": null,
|
||||
//"testing.message.info.lineBackground": null,
|
||||
//"titleBar.border": null,
|
||||
//"toolbar.hoverOutline": null,
|
||||
//"welcomePage.background": null,
|
||||
//"window.activeBorder": null,
|
||||
//"window.inactiveBorder": null
|
||||
},
|
||||
"tokenColors": [
|
||||
{
|
||||
"scope": [
|
||||
"variable.language.this"
|
||||
],
|
||||
"settings": {
|
||||
"fontStyle": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.bold",
|
||||
"settings": {
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"invalid",
|
||||
"markup.italic",
|
||||
"markup.quote"
|
||||
],
|
||||
"settings": {
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "markup.underline",
|
||||
"settings": {
|
||||
"fontStyle": "underline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"source.js.jsx punctuation.section.embedded",
|
||||
"entity.name.tag",
|
||||
"string.other.link.description.title",
|
||||
"support.constant",
|
||||
"support.variable",
|
||||
"support.type",
|
||||
"variable.other.class",
|
||||
"support.class.builtin.js",
|
||||
"support.class.console.js",
|
||||
"meta.property-value",
|
||||
"variable.parameter.keyframe-list",
|
||||
"meta.at-rule.keyframes entity.name.function",
|
||||
"expression.embedded.vue punctuation.definition"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#BBA0FF",
|
||||
"fontStyle": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"entity.other.attribute-name.pseudo-class.css",
|
||||
"entity.name.type.object.console",
|
||||
"variable.language",
|
||||
"variable.parameter.function.language.special.self.python",
|
||||
"storage.type",
|
||||
"entity.other.attribute-name.pseudo-element.css"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#BBA0FF",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"punctuation.definition.string.template"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#BBA0FF",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"entity.other.attribute-name.class.css",
|
||||
"entity.other.attribute-name.parent-selector-suffix.css",
|
||||
"entity.other.attribute-name.parent-selector-suffix.css punctuation.definition.entity.css",
|
||||
"meta.definition.function",
|
||||
"markup.underline.link",
|
||||
"markup.inserted",
|
||||
"meta.function-call",
|
||||
"meta.instance.constructor",
|
||||
"meta.attribute-with-value.class string",
|
||||
"string.other.ref",
|
||||
"string.other.restructuredtext.ref",
|
||||
"variable.function",
|
||||
"entity.name.type",
|
||||
"entity.name.function",
|
||||
"variable.other.object.property",
|
||||
"punctuation.separator.key-value",
|
||||
"meta.definition.function.js",
|
||||
"support.class.component.js",
|
||||
"entity.other.inherited-class",
|
||||
"support.class",
|
||||
"support.function.misc",
|
||||
"support.function",
|
||||
"entity.other.attribute-name.id.css",
|
||||
"entity.other.attribute-name.id.css punctuation",
|
||||
"entity.other.attribute-name.class.css punctuation",
|
||||
"meta.function-call support.function.construct",
|
||||
"entity.other.attribute-name"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#FFDD44"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.type.function.arrow",
|
||||
"settings": {
|
||||
"foreground": "#FFDD44",
|
||||
"fontStyle": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"entity.name.section",
|
||||
"constant.numeric.line-number.match.find-in-files",
|
||||
"markup.heading",
|
||||
"markup.changed",
|
||||
"meta.attribute-with-value.id string",
|
||||
"string",
|
||||
"punctuation.definition.string.begin",
|
||||
"punctuation.definition.string.end",
|
||||
"meta.attribute-selector"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#88CC44"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"keyword",
|
||||
"keyword.control",
|
||||
"constant",
|
||||
"constant.numeric",
|
||||
"constant.language",
|
||||
"constant.other.property",
|
||||
"constant.character.escape",
|
||||
"comment keyword.codetag.notation",
|
||||
"keyword.other.template.begin",
|
||||
"keyword.other.template.end",
|
||||
"markup.raw",
|
||||
"markup.deleted",
|
||||
"meta.property-list.css variable.other",
|
||||
"entity.name.constant.preprocessor",
|
||||
"meta.preprocessor",
|
||||
"punctuation.section.embedded",
|
||||
"punctuation.template-string.element.begin",
|
||||
"punctuation.template-string.element.end",
|
||||
"string.quoted.template punctuation.definition.string.begin",
|
||||
"string.quoted.template punctuation.definition.string.end",
|
||||
"meta.paragraph.markdown meta.dummy.line-break",
|
||||
"meta.paragraph.markdown meta.hard-line-break.markdown",
|
||||
"storage",
|
||||
"storage.class.restructuredtext.ref",
|
||||
"string.other.link.title",
|
||||
"string.other.link.description",
|
||||
"string.regexp punctuation.definition.string.begin",
|
||||
"string.regexp punctuation.definition.string.end",
|
||||
"variable.language.arguments",
|
||||
"storage.modifier",
|
||||
"keyword.operator.new",
|
||||
"keyword.operator",
|
||||
"keyword.operator.spread",
|
||||
"punctuation.section.embedded.end.php source.php",
|
||||
"support.function.construct",
|
||||
"meta.at-rule.keyframes",
|
||||
"meta.at-rule.keyframes entity.other.attribute-name"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#88BBFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"variable.other.substitution"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#88BBFF",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"meta.function-call meta.function-call.arguments",
|
||||
"meta.function-call meta.arguments",
|
||||
"meta.function-call meta.group",
|
||||
"source.json meta.structure.dictionary",
|
||||
"meta.object.member",
|
||||
"punctuation.definition.group",
|
||||
"string.unquoted.label",
|
||||
"variable.other.member",
|
||||
"entity.name.class",
|
||||
"entity.name.namespace",
|
||||
"constant.other",
|
||||
"variable",
|
||||
"variable.other",
|
||||
"variable.other.constant.js",
|
||||
"text.find-in-files",
|
||||
"source",
|
||||
"entity.name.type.module",
|
||||
"source.sql support.function",
|
||||
"support.other.namespace.php"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#FFFFFF",
|
||||
"fontStyle": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"variable.parameter",
|
||||
"parameters variable.function"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#FFFFFF",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"variable.other.property",
|
||||
"support.variable.property",
|
||||
"punctuation.separator.key-value",
|
||||
"meta.object-literal.key",
|
||||
"variable.other.object.property",
|
||||
"variable.object.property",
|
||||
"text.html.basic",
|
||||
"text.html.vue-html",
|
||||
"text.html.php",
|
||||
"text.html.derivative",
|
||||
"punctuation.definition.variable",
|
||||
"punctuation.definition.keyword.scss",
|
||||
"meta.jsx.children.js",
|
||||
"meta.tag.attributes keyword.operator.assignment",
|
||||
"support.type.vendored.property-name.css",
|
||||
"support.type.property-name.json",
|
||||
"variable.other.constant.property"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#BBBBCC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "meta.property-name support.type",
|
||||
"settings": {
|
||||
"foreground": "#BBBBCC",
|
||||
"fontStyle": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"keyword.other.substitution",
|
||||
"keyword.operator.heading.restructuredtext",
|
||||
"keyword.operator.table.row.restructuredtext",
|
||||
"keyword.operator.table.data.restructuredtext",
|
||||
"punctuation",
|
||||
"markup.ignored",
|
||||
"markup.untracked",
|
||||
"meta.brace.round",
|
||||
"meta.brace.square",
|
||||
"meta.brace.curly",
|
||||
"meta.delimiter.comma.js",
|
||||
"meta.function-call.without-arguments.js",
|
||||
"meta.function-call.method.without-arguments.js",
|
||||
"source.scss",
|
||||
"string source punctuation.section.embedded",
|
||||
"punctuation.definition.tag.begin source",
|
||||
"source.php"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#9999AA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"comment",
|
||||
"comment punctuation"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#888899",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "token.info-token",
|
||||
"settings": {
|
||||
"foreground": "#6796E6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "token.warn-token",
|
||||
"settings": {
|
||||
"foreground": "#CD9731"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "token.error-token",
|
||||
"settings": {
|
||||
"foreground": "#F44747"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "token.debug-token",
|
||||
"settings": {
|
||||
"foreground": "#B267E6"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,41 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Spark Client",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/Debug/bin/net6.0-windows/Spark.exe",
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net6.0-windows",
|
||||
"enableStepFiltering": false,
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": "Spark Test",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/Debug/bin/net6.0/sparkcmd.exe",
|
||||
"args": ["test", "${input:test}"],
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net6.0-windows",
|
||||
"enableStepFiltering": false,
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": "Attach (.NET Core)",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"id": "test",
|
||||
"description": "The test(s) to run",
|
||||
"type": "promptString"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"cmake.configureOnOpen": false,
|
||||
"workbench.colorTheme": "Default Dark+",
|
||||
"C_Cpp.intelliSenseEngine": "Disabled",
|
||||
"files.associations": {
|
||||
"*.js": "javascript",
|
||||
"*.conf": "jsonc",
|
||||
"array": "cpp",
|
||||
"xtree": "cpp",
|
||||
"chrono": "cpp",
|
||||
"*.ipp": "cpp",
|
||||
"optional": "cpp",
|
||||
"regex": "cpp",
|
||||
"system_error": "cpp",
|
||||
"format": "cpp",
|
||||
"future": "cpp",
|
||||
"istream": "cpp",
|
||||
"memory": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"variant": "cpp",
|
||||
"xlocmes": "cpp",
|
||||
"xlocmon": "cpp",
|
||||
"xlocnum": "cpp",
|
||||
"xloctime": "cpp",
|
||||
"xutility": "cpp",
|
||||
"xstring": "cpp",
|
||||
"string": "cpp",
|
||||
"cstdint": "cpp"
|
||||
},
|
||||
|
||||
"files.exclude": {
|
||||
"**/.g.cs": true,
|
||||
"**/.g.i.cs": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build Spark Client",
|
||||
"type": "process",
|
||||
"command": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Common7\\Tools\\VsDevCmd.bat",
|
||||
"args": [
|
||||
"-arch=x64",
|
||||
"-host_arch=x64",
|
||||
"&&",
|
||||
"${workspaceRoot}\\tools\\buildspark.cmd"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "new",
|
||||
"showReuseMessage": false,
|
||||
"clear": false,
|
||||
"close": false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"label": "Run Spark Client",
|
||||
"type": "process",
|
||||
"command": "${workspaceRoot}\\build\\Debug\\bin\\net6.0-windows\\Spark.exe",
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "shared",
|
||||
"showReuseMessage": true,
|
||||
"clear": false
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(doc)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/tools/safe_dep_glob.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/tools/Protobuf.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/safe_dep_glob.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/Protobuf.cmake)
|
||||
|
||||
# DEPENDENCIES
|
||||
set(DOC_GLOBS
|
||||
|
||||
+1
-1
Submodule docker/linux updated: 05967d0f18...6537812262.
+1
-1
Submodule externals updated: 1dffb78a8e...4d96613ca8.
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "2.1.508",
|
||||
"version": "6.0.200",
|
||||
"rollForward": "latestMajor"
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ pycodestyle==2.7.0
|
||||
pycparser==2.20
|
||||
pylint==2.10.2
|
||||
PyMeta3==0.5.1
|
||||
termcolor==1.1.0
|
||||
toml==0.10.2
|
||||
wrapt==1.12.1
|
||||
yapf==0.31.0
|
||||
+32
-22
@@ -1,10 +1,10 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30114.105
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32922.545
|
||||
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", "{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
|
||||
EndProject
|
||||
@@ -12,15 +12,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\spar
|
||||
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", "{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40} = {9FA60215-26AF-3EB7-AB89-D4F4B126EF40}
|
||||
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25} = {FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}
|
||||
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_websocket", "src\client\spark_websocket\spark_websocket.csproj", "{3201359D-C071-4089-9EDE-B04D759F1508}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api_server", "src\client\spark_api_server\spark_api_server.csproj", "{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -37,14 +39,14 @@ Global
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.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
|
||||
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Debug|x64.Build.0 = Debug|x64
|
||||
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Release|x64.ActiveCfg = Release|x64
|
||||
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Release|x64.Build.0 = Release|x64
|
||||
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
|
||||
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Debug|x64.Build.0 = Debug|x64
|
||||
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Release|x64.ActiveCfg = Release|x64
|
||||
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Release|x64.Build.0 = Release|x64
|
||||
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|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}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
@@ -69,14 +71,6 @@ Global
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.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
|
||||
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Debug|x64.Build.0 = Debug|x64
|
||||
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Release|x64.ActiveCfg = Release|x64
|
||||
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Release|x64.Build.0 = Release|x64
|
||||
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|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}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
@@ -93,6 +87,22 @@ Global
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.Build.0 = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.ActiveCfg = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.Build.0 = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.Build.0 = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.ActiveCfg = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.Build.0 = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<EnableDefaultContentItems>False</EnableDefaultContentItems>
|
||||
<ShowMissingItemTypes>false</ShowMissingItemTypes>
|
||||
<Configuration Condition="'$(configuration)'==''">Debug</Configuration>
|
||||
<EnablePreviewFeatures>true</EnablePreviewFeatures>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Output">
|
||||
|
||||
@@ -52,8 +52,7 @@
|
||||
<Exec Command="set PYTHONPATH=$(SparkRoot)\.venv\Scripts\python" />
|
||||
<Exec
|
||||
Command="
|
||||
$(SparkRoot)\tools\build_protos.cmd ^
|
||||
%(Proto3.FullPath) ^
|
||||
$(protoc) %* %(Proto3.FullPath) ^
|
||||
--error_format=msvs ^
|
||||
--proto_path=$(SourceRoot) ^
|
||||
--plugin="protoc-gen-service=$(ProtocPluginBase)\plugin.cmd" ^
|
||||
@@ -68,6 +67,16 @@
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="RemoveSystemRuntimeFromRefPack"
|
||||
BeforeTargets="_HandlePackageFileConflicts"
|
||||
Condition="'@(Reference -> WithMetadataValue('NugetPackageId', 'System.Runtime.Experimental'))' != ''">
|
||||
<ItemGroup>
|
||||
<Reference Remove="@(Reference)"
|
||||
Condition="$([System.String]::Copy(%(Reference.Identity)).Contains('System.Runtime.dll')) and
|
||||
'%(Reference.NuGetPackageId)' == 'Microsoft.NETCore.App.Ref'" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target
|
||||
Name="AfterClean"
|
||||
AfterTargets="Clean">
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using bts.api.analytics;
|
||||
|
||||
using mbts.analytics;
|
||||
using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
@@ -12,9 +15,9 @@ namespace mbts.spark {
|
||||
readonly AnalyticsExpirationParameters _committed_value;
|
||||
readonly Property<bool> _is_selected;
|
||||
|
||||
readonly Property<SecurityExpiration> _driver;
|
||||
readonly Property<SecurityExpiration> _deliverable;
|
||||
readonly Property<SecurityExpiration> _roll_schedule;
|
||||
readonly Property<ExpirationDriverImmutable?> _driver;
|
||||
readonly Property<SecurityExpiration?> _deliverable;
|
||||
readonly Property<SecurityExpiration?> _roll_schedule;
|
||||
readonly Property<double> _roll_target;
|
||||
readonly Property<double> _riskless_rate;
|
||||
readonly Property<double> _settlement_price;
|
||||
@@ -33,18 +36,19 @@ namespace mbts.spark {
|
||||
|
||||
bool _is_last_row_of_month_group;
|
||||
|
||||
public AnalyticsExpirationParametersRowVM(AnalyticsExpirationParametersVM owner, AnalyticsExpirationParameters committed_value) {
|
||||
this.owner = owner ?? throw new ArgumentNullException(nameof(owner));
|
||||
_committed_value = committed_value ?? throw new ArgumentNullException(nameof(committed_value));
|
||||
public AnalyticsExpirationParametersRowVM(
|
||||
AnalyticsExpirationParametersVM owner, AnalyticsExpirationParameters committed_value) {
|
||||
this.owner = owner;
|
||||
_committed_value = committed_value;
|
||||
security = committed_value.security ?? throw new ArgumentException("security must be non-null", nameof(committed_value));
|
||||
|
||||
_is_selected = backing(nameof(is_selected), false);
|
||||
_is_selected.Changed += (oldval, newval) => is_selected_changed?.Invoke(newval);
|
||||
|
||||
var is_dirty_srcs = new List<IObservable<bool>>();
|
||||
(_driver, _is_driver_dirty) = mk_cell_props(nameof(driver), committed_value.driver_security);
|
||||
(_deliverable, _is_deliverable_dirty) = mk_cell_props(nameof(deliverable), committed_value.deliverable_security);
|
||||
(_roll_schedule, _is_roll_schedule_dirty) = mk_cell_props(nameof(roll_schedule), committed_value.roll_schedule_expiration);
|
||||
(_driver, _is_driver_dirty) = mk_cell_props<ExpirationDriverImmutable?>(nameof(driver), committed_value.driver);
|
||||
(_deliverable, _is_deliverable_dirty) = mk_cell_props<SecurityExpiration?>(nameof(deliverable), committed_value.deliverable_security);
|
||||
(_roll_schedule, _is_roll_schedule_dirty) = mk_cell_props<SecurityExpiration?>(nameof(roll_schedule), committed_value.roll_schedule_expiration);
|
||||
(_roll_target, _is_roll_target_dirty) = mk_cell_props(nameof(roll_target), committed_value.roll_target);
|
||||
(_riskless_rate, _is_riskless_rate_dirty) = mk_cell_props(nameof(riskless_rate), committed_value.riskless_rate);
|
||||
(_settlement_price, _is_settlement_price_dirty) = mk_cell_props(nameof(settlement_price), committed_value.settlement_price);
|
||||
@@ -64,13 +68,22 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<bool> is_selected_changed;
|
||||
public event Action<bool>? is_selected_changed;
|
||||
|
||||
public AnalyticsExpirationParametersVM owner { get; }
|
||||
public SecurityExpiration security { get; }
|
||||
public SecurityExpiration driver { get => _driver.Value; set => _driver.set(value); }
|
||||
public SecurityExpiration deliverable { get => _deliverable.Value; set => _deliverable.set(value); }
|
||||
public SecurityExpiration roll_schedule { get => _roll_schedule.Value; set => _roll_schedule.set(value); }
|
||||
public ExpirationDriverImmutable? driver {
|
||||
get => _driver.Value;
|
||||
set => _driver.set(value);
|
||||
}
|
||||
public SecurityExpiration? deliverable {
|
||||
get => _deliverable.Value;
|
||||
set => _deliverable.set(value);
|
||||
}
|
||||
public SecurityExpiration? roll_schedule {
|
||||
get => _roll_schedule.Value;
|
||||
set => _roll_schedule.set(value);
|
||||
}
|
||||
public AnalyticsExpirationParameters original_params => _committed_value;
|
||||
|
||||
public double roll_target { get => _roll_target.Value; set => _roll_target.set(value); }
|
||||
@@ -102,15 +115,15 @@ namespace mbts.spark {
|
||||
public AnalyticsExpirationParameters candidate_value => new(
|
||||
security,
|
||||
driver,
|
||||
deliverable.is_empty() ? null : deliverable,
|
||||
roll_schedule.is_empty() ? null : roll_schedule,
|
||||
deliverable?.is_empty() ?? false ? null : deliverable,
|
||||
roll_schedule?.is_empty() ?? false ? null : roll_schedule,
|
||||
roll_target,
|
||||
riskless_rate,
|
||||
settlement_price,
|
||||
delta_beta,
|
||||
vega_beta);
|
||||
|
||||
public IObservable<SecurityExpiration> observe_roll_schedule() =>
|
||||
public IObservable<SecurityExpiration?> observe_roll_schedule() =>
|
||||
_roll_schedule.observe_current(true);
|
||||
|
||||
public IObservable<bool> observe_roll_schedule_dirty() =>
|
||||
@@ -120,7 +133,7 @@ namespace mbts.spark {
|
||||
_is_dirty.observe_current(true);
|
||||
|
||||
public void revert() {
|
||||
driver = _committed_value.driver_security;
|
||||
driver = _committed_value.driver;
|
||||
deliverable = _committed_value.deliverable_security;
|
||||
roll_schedule = _committed_value.roll_schedule_expiration;
|
||||
roll_target = _committed_value.roll_target;
|
||||
@@ -133,11 +146,11 @@ namespace mbts.spark {
|
||||
public override string ToString() =>
|
||||
$"sec: {security}; drv: {driver}; dlv: {deliverable}; roll: {roll_schedule} @ {roll_target}";
|
||||
|
||||
public bool Equals(AnalyticsExpirationParametersRowVM other) =>
|
||||
public bool Equals(AnalyticsExpirationParametersRowVM? other) =>
|
||||
other is not null &&
|
||||
security.Equals(other.security);
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
public override bool Equals(object? obj) =>
|
||||
Equals(obj as AnalyticsExpirationParametersRowVM);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace mbts.spark {
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using bts.api;
|
||||
using bts.api.analytics;
|
||||
using bts.collections;
|
||||
using bts.reactive;
|
||||
using bts.utils;
|
||||
|
||||
@@ -12,11 +15,17 @@
|
||||
using mbts.ui.utility;
|
||||
using mbts.utils;
|
||||
|
||||
using Spark.Core;
|
||||
using Spark.Core.Collections;
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.ViewModel.Commands;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
@@ -26,25 +35,33 @@
|
||||
class AnalyticsExpirationParametersVM : DisposableViewModelBase, IHandleRowSelection {
|
||||
readonly IBus _bus;
|
||||
readonly ObservableCollection<AnalyticsExpirationParameters> _parameters = new();
|
||||
readonly DeferrableActionWrapper _sync_visible_rows;
|
||||
readonly Property<AnalyticsExpirationParametersRowVM> _copy_row_source;
|
||||
readonly DeferrableAction _sync_visible_rows;
|
||||
readonly Property<AnalyticsExpirationParametersRowVM?> _copy_row_source;
|
||||
readonly Property<bool> _auto_copy_rolls_is_checked;
|
||||
readonly Property<bool> _auto_copy_rates_is_checked;
|
||||
readonly DelegateProperty<bool> _is_dirty;
|
||||
readonly HashSet<AnalyticsExpirationParametersRowVM> _selected_rows = new();
|
||||
readonly ObservableHashSet<AnalyticsExpirationParametersRowVM> _selected_rows = new();
|
||||
readonly DeferrableAction _raise_selected_rows_changed;
|
||||
readonly IRaiseCanExecuteChangedCommand _set_driver_to_nearest_exp_cmd;
|
||||
|
||||
AnalyticsExpirationParametersMap _parameter_map;
|
||||
bool _auto_copy_rolls_is_checked;
|
||||
bool _auto_copy_rates_is_checked;
|
||||
AnalyticsExpirationParametersMap? _parameter_map;
|
||||
(ICommand cmd, IDisposable can_exe_sub)? _smart_copy_roll_target_to_selection_cmd;
|
||||
(ICommand cmd, IDisposable can_exe_sub)? _smart_copy_riskless_rate_to_selection_cmd;
|
||||
|
||||
public AnalyticsExpirationParametersVM(IBus bus, AnalyticsExpirationParametersSettings startup_data) {
|
||||
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
|
||||
public AnalyticsExpirationParametersVM(
|
||||
IBus bus, AnalyticsExpirationParametersSettings startup_data) {
|
||||
_bus = bus;
|
||||
_auto_copy_rates_is_checked = backing(nameof(auto_copy_rates_is_checked), false);
|
||||
_auto_copy_rolls_is_checked = backing(nameof(auto_copy_rolls_is_checked), false);
|
||||
_raise_selected_rows_changed = new(() => selected_rows_changed?.Invoke(_selected_rows));
|
||||
var selected_symbol_ref_count = new RefCountMap<string>();
|
||||
_sync_visible_rows = new(() =>
|
||||
visible_rows.sync_with(rows.Where(x => selected_symbol_ref_count.ContainsKey(x.security.symbol))));
|
||||
visible_rows.sync_with(
|
||||
rows.Where(x => selected_symbol_ref_count.ContainsKey(x.security.symbol))));
|
||||
non_options_with_empty = new ObservableAggregateCollection<SecurityExpiration>(
|
||||
new() { SecurityExpiration.empty }, non_options);
|
||||
_copy_row_source = backing<AnalyticsExpirationParametersRowVM>(nameof(copy_row_source));
|
||||
|
||||
_copy_row_source = backing<AnalyticsExpirationParametersRowVM?>(nameof(copy_row_source));
|
||||
_is_dirty = backing(nameof(is_dirty), () => rows.Any(r => r.is_dirty));
|
||||
|
||||
if (startup_data is not null) {
|
||||
@@ -55,41 +72,57 @@
|
||||
auto_copy_rates_is_checked = startup_data.auto_copy_rates_is_checked;
|
||||
}
|
||||
|
||||
var explicit_drivers = new ObservableCollection<ExpirationDriverImmutable>();
|
||||
drivers = ObservableAggregateCollection.create(
|
||||
new() { new ExpirationDriverImmutable(new() { TimeWeightedInterpolated = new() }) },
|
||||
explicit_drivers);
|
||||
_set_driver_to_nearest_exp_cmd = new Command(
|
||||
() => _set_driver_to_nearest_exp(_selected_rows), () => _selected_rows.Count > 0);
|
||||
commit_cmd = ObservantCommand.create(_commit, out var can_commit_observer);
|
||||
revert_cmd = ObservantCommand.create(_revert, out var can_revert_observer);
|
||||
selected_rows_changed += _ => _set_driver_to_nearest_exp_cmd.RaiseCanExecuteChanged();
|
||||
|
||||
_dispose = Disposable.Create(
|
||||
_selected_rows.Subscribe((s, e) => _raise_selected_rows_changed.Invoke()),
|
||||
ObservableAutoWrapper.connect(_parameters, rows, p => new(this, p), r => r.Dispose()),
|
||||
rows.Subscribe((s, e) => _sync_visible_rows.execute()),
|
||||
ObservableAutoWrapper.connect(
|
||||
non_options,
|
||||
explicit_drivers,
|
||||
sec => new ExpirationDriverImmutable(new() { Security = sec.to_api_sec_exp() })),
|
||||
rows.Subscribe((s, e) => _sync_visible_rows.Invoke()),
|
||||
_bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(
|
||||
CompositeObserver.create(
|
||||
Observer.Create<AnalyticsExpirationParametersMap>(_on_parameter_map),
|
||||
can_commit_observer.wrap<bool, AnalyticsExpirationParametersMap>(m => m is not null))),
|
||||
ObservableAutoWrapper.connect_item_hooks(selected_symbols, sym => {
|
||||
if (selected_symbol_ref_count.increment_adds_key(sym)) {
|
||||
_sync_visible_rows.execute();
|
||||
_sync_visible_rows.Invoke();
|
||||
}
|
||||
return Disposable.Create(() => {
|
||||
if (selected_symbol_ref_count.decrement_removes_key(sym)) {
|
||||
_sync_visible_rows.execute();
|
||||
_sync_visible_rows.Invoke();
|
||||
}
|
||||
});
|
||||
}),
|
||||
ObservableAutoWrapper.connect_item_hooks(rows, r => r.observe_is_dirty().Subscribe(_ => _is_dirty.refresh())),
|
||||
ObservableAutoWrapper.connect_item_hooks(
|
||||
rows, r => r.observe_is_dirty().Subscribe(_ => _is_dirty.refresh())),
|
||||
_is_dirty.observe_current(true).OnDispatcher().Subscribe(can_revert_observer),
|
||||
Disposable.wrap_collection(rows),
|
||||
Disposable.Create(() => {
|
||||
rows.DisposeAll();
|
||||
_smart_copy_roll_target_to_selection_cmd?.can_exe_sub?.Dispose();
|
||||
_smart_copy_riskless_rate_to_selection_cmd?.can_exe_sub?.Dispose();
|
||||
}));
|
||||
}
|
||||
|
||||
public event Action<IReadOnlySet<AnalyticsExpirationParametersRowVM>>? selected_rows_changed;
|
||||
|
||||
public ObservableCollection<SecurityExpiration> non_options { get; } = new();
|
||||
public IReadOnlyObservableCollection<ExpirationDriverImmutable> drivers { get; }
|
||||
public ObservableCollection<SecurityExpiration> non_options_with_empty { get; } = new();
|
||||
|
||||
public ObservableCollection<AnalyticsExpirationParametersRowVM> rows { get; } = new();
|
||||
public ObservableCollection<AnalyticsExpirationParametersRowVM> visible_rows { get; } = new();
|
||||
public AnalyticsExpirationParametersRowVM copy_row_source {
|
||||
public AnalyticsExpirationParametersRowVM? copy_row_source {
|
||||
get => _copy_row_source.Value;
|
||||
set => _copy_row_source.set(value);
|
||||
}
|
||||
@@ -100,18 +133,29 @@
|
||||
public bool is_dirty => _is_dirty.Value;
|
||||
|
||||
public bool auto_copy_rolls_is_checked {
|
||||
get => _auto_copy_rolls_is_checked;
|
||||
set => Set(ref _auto_copy_rolls_is_checked, value);
|
||||
get => _auto_copy_rolls_is_checked.Value;
|
||||
set => _auto_copy_rolls_is_checked.set(value);
|
||||
}
|
||||
public IObservable<bool> observe_auto_copy_rolls() =>
|
||||
_auto_copy_rolls_is_checked.observe_current(true);
|
||||
|
||||
public bool auto_copy_rates_is_checked {
|
||||
get => _auto_copy_rates_is_checked;
|
||||
set => Set(ref _auto_copy_rates_is_checked, value);
|
||||
get => _auto_copy_rates_is_checked.Value;
|
||||
set => _auto_copy_rates_is_checked.set(value);
|
||||
}
|
||||
public IObservable<bool> observe_auto_copy_rates() =>
|
||||
_auto_copy_rates_is_checked.observe_current(true);
|
||||
|
||||
public ICommand toggle_auto_copy_rates_cmd =>
|
||||
new Command(() => auto_copy_rates_is_checked = !auto_copy_rates_is_checked);
|
||||
public ICommand toggle_auto_copy_rolls_cmd =>
|
||||
new Command(() => auto_copy_rolls_is_checked = !auto_copy_rolls_is_checked);
|
||||
|
||||
public ICommand commit_cmd { get; }
|
||||
public ICommand revert_cmd { get; }
|
||||
|
||||
public ICommand set_driver_to_nearest_exp_cmd => _set_driver_to_nearest_exp_cmd;
|
||||
|
||||
public ICommand copy_driver_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.driver = f.driver);
|
||||
public ICommand copy_deliverable_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.deliverable = f.deliverable);
|
||||
public ICommand copy_roll_schedule_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.roll_schedule = f.roll_schedule);
|
||||
@@ -138,7 +182,7 @@
|
||||
|
||||
public IEnumerable<SecurityExpiration> get_smart_copy_roll_exps(
|
||||
SecurityExpiration roll_schedule_expiration) {
|
||||
foreach (var (exp, exp_params) in _parameter_map?.exp_map.empty_if_null()) {
|
||||
foreach (var (exp, exp_params) in (_parameter_map?.exp_map).empty_if_null()) {
|
||||
if (exp_params.roll_schedule_expiration.Equals(roll_schedule_expiration)) {
|
||||
yield return exp;
|
||||
}
|
||||
@@ -152,17 +196,38 @@
|
||||
auto_copy_rolls_is_checked = auto_copy_rolls_is_checked
|
||||
};
|
||||
|
||||
Action<AnalyticsExpirationParametersRowVM> _copy_to_selection(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
|
||||
void _set_driver_to_nearest_exp(IEnumerable<AnalyticsExpirationParametersRowVM> rows) {
|
||||
Func<ExpirationDriverImmutable, bool> is_unexpired = (d) => {
|
||||
var st = d.Security.to_sec_exp().security_tuple.to_api_sec_tuple();
|
||||
var exp = d.Security.Expiration.date_time();
|
||||
return SecurityExpirationHelper.is_unexpired(st, exp);
|
||||
};
|
||||
foreach (var r in rows) {
|
||||
if (drivers
|
||||
.Where(d => d.HasSecurity && d.Security.Symbol == r.security.symbol)
|
||||
.Where(d => is_unexpired(d))
|
||||
.TryGetMinElement(
|
||||
d => (r.security.expiration - d.Security.Expiration.date_time()).Ticks.abs(),
|
||||
out var nearest_exp)) {
|
||||
r.driver = nearest_exp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Action<AnalyticsExpirationParametersRowVM> _copy_to_selection(
|
||||
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
|
||||
from_row => {
|
||||
foreach (var to_row in _selected_rows) {
|
||||
copy_to_row(from_row, to_row);
|
||||
}
|
||||
};
|
||||
|
||||
ICommand _copy_to_selection_cmd(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
|
||||
ICommand _copy_to_selection_cmd(
|
||||
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
|
||||
Command.create(_copy_to_selection(copy_to_row));
|
||||
|
||||
Action<AnalyticsExpirationParametersRowVM> _smart_copy_to_selection(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
|
||||
Action<AnalyticsExpirationParametersRowVM> _smart_copy_to_selection(
|
||||
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
|
||||
from_row => {
|
||||
foreach (var to_row in _get_smart_copy_roll_target_rows(from_row)) {
|
||||
copy_to_row(from_row, to_row);
|
||||
@@ -171,21 +236,26 @@
|
||||
|
||||
(ICommand cmd, IDisposable can_exe_sub) _smart_copy_to_selection_cmd(
|
||||
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) {
|
||||
var cmd = ObservantCommand.create(
|
||||
_smart_copy_to_selection(copy_to_row), observe_can_execute, out var can_exe_observer);
|
||||
var can_exe_sub = _copy_row_source.observe_current(true).OnDispatcher().Subscribe(can_exe_observer);
|
||||
var copy_fn = _smart_copy_to_selection(copy_to_row);
|
||||
var cmd = ObservantCommand.create<AnalyticsExpirationParametersRowVM?>(
|
||||
r => copy_fn(r ?? throw new InvalidOperationException()),
|
||||
observe_can_execute,
|
||||
out var can_exe_observer);
|
||||
var can_exe_sub = _copy_row_source.observe_current(true).OnDispatcher()
|
||||
.Subscribe(can_exe_observer);
|
||||
return (cmd, can_exe_sub);
|
||||
|
||||
static IObservable<bool> observe_can_execute(AnalyticsExpirationParametersRowVM row) =>
|
||||
static IObservable<bool> observe_can_execute(AnalyticsExpirationParametersRowVM? row) =>
|
||||
row is null ?
|
||||
Observable.Return(false) :
|
||||
row.observe_roll_schedule()
|
||||
.CombineLatest(row.observe_roll_schedule_dirty(), (rs, rs_dirty) => (rs, rs_dirty))
|
||||
.Select(tup => !tup.rs.is_empty() && !tup.rs_dirty)
|
||||
.Select(tup => !tup.rs?.is_empty() ?? false && !tup.rs_dirty)
|
||||
.OnDispatcher();
|
||||
}
|
||||
|
||||
IEnumerable<AnalyticsExpirationParametersRowVM> _get_smart_copy_roll_target_rows(AnalyticsExpirationParametersRowVM row) {
|
||||
IEnumerable<AnalyticsExpirationParametersRowVM> _get_smart_copy_roll_target_rows(
|
||||
AnalyticsExpirationParametersRowVM row) {
|
||||
var target_exps = get_smart_copy_roll_exps(
|
||||
row.original_params.roll_schedule_expiration)
|
||||
.ToHashSet();
|
||||
@@ -207,11 +277,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(_parameter_map))]
|
||||
void _on_parameter_map(AnalyticsExpirationParametersMap parameter_map) {
|
||||
bool is_first_update = _parameter_map is null;
|
||||
_parameter_map = parameter_map ?? throw new ArgumentNullException(nameof(parameter_map));
|
||||
_parameter_map = parameter_map;
|
||||
_parameters.sync_with(parameter_map.get_sorted_exps().Select(parameter_map.get_parameter));
|
||||
non_options.sync_with(parameter_map.get_sorted_exps().Where(exp => exp.security_type != SecurityType.Option));
|
||||
non_options.sync_with(
|
||||
parameter_map.get_sorted_exps().Where(exp => exp.security_type != SecurityType.Option));
|
||||
|
||||
// Set `is_last_row_of_month_group` for each row
|
||||
foreach (var exp_rows in rows.GroupBy(r => r.security.expiration.Month)) {
|
||||
@@ -223,7 +295,7 @@
|
||||
}
|
||||
|
||||
symbols.sync_with(_parameters.Select(p => p.security.symbol).Distinct().Ordered());
|
||||
using var _ = _sync_visible_rows.defer_execution();
|
||||
using var _ = _sync_visible_rows.defer();
|
||||
if (is_first_update) {
|
||||
// select all symbols on first update
|
||||
selected_symbols.sync_with(symbols);
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
xmlns:u="clr-namespace:mbts.ui"
|
||||
xmlns:cv="clr-namespace:mbts.ui.converters"
|
||||
xmlns:shell="clr-namespace:mbts.ui.shell"
|
||||
Background="{StaticResource CommonBackground}">
|
||||
Background="{u:BTSBrush UI.common_background}">
|
||||
<UserControl.Resources>
|
||||
<cv:DoubleTextConverter x:Key="DoubleTextConverter" />
|
||||
<cv:DoubleTextConverter
|
||||
x:Key="RisklessRateConverter"
|
||||
Multiplier="100" />
|
||||
<shell:ExpTextConverter
|
||||
x:Key="ExpirationTextConverter"
|
||||
ShowSymbol="True"
|
||||
MapExp="True" />
|
||||
<DataTemplate x:Key="ExpirationTemplate">
|
||||
<TextBlock Text="{Binding Converter={StaticResource ExpirationTextConverter}}">
|
||||
|
||||
<CollectionViewSource x:Key="Drivers" Source="{Binding drivers}" />
|
||||
<CollectionViewSource x:Key="NonOptionsWithEmpty" Source="{Binding non_options_with_empty}" />
|
||||
|
||||
<DataTemplate x:Key="DriverTemplate">
|
||||
<TextBlock Text="{Binding Converter={x:Static shell:AnalyticsExpirationParametersView.driver_display_text_converter}}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
@@ -30,9 +30,24 @@
|
||||
<Setter
|
||||
Property="FontStyle"
|
||||
Value="Italic" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="ExpirationTemplate">
|
||||
<TextBlock Text="{Binding Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_text_converter}}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
<Trigger
|
||||
Property="Text"
|
||||
Value="None">
|
||||
<Setter
|
||||
Property="Foreground"
|
||||
Value="Gray" />
|
||||
Property="FontStyle"
|
||||
Value="Italic" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
@@ -102,6 +117,20 @@
|
||||
CommandParameter="{Binding}"
|
||||
/>
|
||||
</ContextMenu>
|
||||
|
||||
<Style x:Key="TextBlockCellElement" TargetType="TextBlock">
|
||||
<Setter
|
||||
Property="Foreground"
|
||||
Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=DataGridCell}}" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ComboBoxCellElement" TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
|
||||
<Setter
|
||||
Property="Foreground"
|
||||
Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=DataGridCell}}" />
|
||||
<Setter Property="Margin" Value="2" />
|
||||
<Setter Property="IsSynchronizedWithCurrentItem" Value="False" />
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.Resources>
|
||||
@@ -124,17 +153,23 @@
|
||||
SelectedItems="{Binding selected_symbols}"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="5,2,2,2"
|
||||
TextBlock.Foreground="Black"
|
||||
HeaderContent="Symbols"
|
||||
ShowSelectAll="True"
|
||||
/>
|
||||
ShowSelectAll="True">
|
||||
<c:ComboCheckBox.HeaderContentTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}" Foreground="{u:BTSColor UI.default_text}" />
|
||||
</DataTemplate>
|
||||
</c:ComboCheckBox.HeaderContentTemplate>
|
||||
</c:ComboCheckBox>
|
||||
|
||||
<WrapPanel>
|
||||
<TextBlock Margin="5,5,0,0" Text="Auto copy rolls:" />
|
||||
<TextBlock
|
||||
Margin="5,5,0,0" Foreground="{u:BTSBrush UI.default_text}" Text="Auto copy rolls:" />
|
||||
<CheckBox Margin="5,5,10,0" IsChecked="{Binding auto_copy_rolls_is_checked}" />
|
||||
</WrapPanel>
|
||||
<WrapPanel>
|
||||
<TextBlock Margin='0,5,0,0' Text="Auto copy rates:" />
|
||||
<TextBlock
|
||||
Margin='0,5,0,0' Foreground="{u:BTSBrush UI.default_text}" Text="Auto copy rates:" />
|
||||
<CheckBox Margin="5,5,0,0" IsChecked="{Binding auto_copy_rates_is_checked}" />
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
@@ -142,8 +177,8 @@
|
||||
x:Name="_grid"
|
||||
Grid.Row="1"
|
||||
ItemsSource="{Binding visible_rows}"
|
||||
AlternatingRowBackground="{u:BTSColor MarketData.driver_background}"
|
||||
VerticalGridLinesBrush="Gray"
|
||||
Background="Transparent"
|
||||
VerticalGridLinesBrush="{u:BTSColor Grid.grid_line}"
|
||||
EnableRowVirtualization="True"
|
||||
EnableColumnVirtualization="True"
|
||||
CanUserAddRows="False"
|
||||
@@ -156,35 +191,10 @@
|
||||
SelectionUnit="FullRow"
|
||||
SelectedUnits="{Binding selected_rows}"
|
||||
PreviewMouseRightButtonUp="_grid_PreviewMouseRightButtonUp">
|
||||
<DataGrid.Resources>
|
||||
<Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Style.Triggers>
|
||||
<Trigger
|
||||
Property="IsSelected"
|
||||
Value="True">
|
||||
<Setter
|
||||
Property="Background"
|
||||
Value="{u:BTSColor Grid.grid_selection_background}" />
|
||||
<Setter
|
||||
Property="BorderBrush"
|
||||
Value="{u:BTSColor Grid.grid_selection_background}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.Resources>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<c:DataGridEx.RowStyle>
|
||||
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
|
||||
<Setter Property="IsSelected" Value="{Binding is_selected, Mode=TwoWay}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Style.Triggers>
|
||||
<Trigger
|
||||
Property="IsSelected"
|
||||
Value="true">
|
||||
<Setter
|
||||
Property="Background"
|
||||
Value="{u:BTSColor Grid.grid_selection_background}" />
|
||||
</Trigger>
|
||||
<DataTrigger
|
||||
Binding="{Binding is_last_row_of_month_group}"
|
||||
Value="True">
|
||||
@@ -197,7 +207,7 @@
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
</c:DataGridEx.RowStyle>
|
||||
<DataGrid.ColumnHeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<Setter
|
||||
@@ -209,9 +219,6 @@
|
||||
<Setter
|
||||
Property="HorizontalContentAlignment"
|
||||
Value="Center" />
|
||||
<Setter
|
||||
Property="BorderThickness"
|
||||
Value="0,0,1,0" />
|
||||
<Setter
|
||||
Property="BorderBrush"
|
||||
Value="Black" />
|
||||
@@ -226,7 +233,7 @@
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn
|
||||
Header="Security"
|
||||
Binding="{Binding security, Converter={StaticResource ExpirationTextConverter}}"
|
||||
Binding="{Binding security, Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_text_converter}}"
|
||||
IsReadOnly="True">
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style
|
||||
@@ -238,9 +245,6 @@
|
||||
<Setter
|
||||
Property="Foreground"
|
||||
Value="{u:BTSColor Name=header_text}" />
|
||||
<Setter
|
||||
Property="BorderThickness"
|
||||
Value="0" />
|
||||
<Setter
|
||||
Property="VerticalContentAlignment"
|
||||
Value="Center" />
|
||||
@@ -287,9 +291,7 @@
|
||||
<DataTrigger
|
||||
Binding="{Binding is_driver_dirty}"
|
||||
Value="True">
|
||||
<Setter
|
||||
Property="BorderBrush"
|
||||
Value="Red" />
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
@@ -297,10 +299,10 @@
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<ComboBox
|
||||
ItemsSource="{Binding DataContext.non_options, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
|
||||
ItemTemplate="{StaticResource ExpirationTemplate}"
|
||||
ItemsSource="{Binding Source={StaticResource Drivers}}"
|
||||
ItemTemplate="{StaticResource DriverTemplate}"
|
||||
SelectedItem="{Binding driver, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="2" />
|
||||
Style="{StaticResource ComboBoxCellElement}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
@@ -318,20 +320,28 @@
|
||||
<DataTrigger
|
||||
Binding="{Binding is_deliverable_dirty}"
|
||||
Value="True">
|
||||
<Setter
|
||||
Property="BorderBrush"
|
||||
Value="Red" />
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding is_deliverable_dirty}" Value="False" />
|
||||
<Condition Binding="{Binding
|
||||
deliverable,
|
||||
Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_is_defined_converter}}"
|
||||
Value="False" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.default_foreground_dark}" />
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<ComboBox
|
||||
ItemsSource="{Binding DataContext.non_options_with_empty, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
|
||||
ItemsSource="{Binding Source={StaticResource NonOptionsWithEmpty}}"
|
||||
ItemTemplate="{StaticResource ExpirationTemplate}"
|
||||
SelectedItem="{Binding deliverable, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="2" />
|
||||
Style="{StaticResource ComboBoxCellElement}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
@@ -349,20 +359,28 @@
|
||||
<DataTrigger
|
||||
Binding="{Binding is_roll_schedule_dirty}"
|
||||
Value="True">
|
||||
<Setter
|
||||
Property="BorderBrush"
|
||||
Value="Red" />
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
|
||||
</DataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding is_roll_schedule_dirty}" Value="False" />
|
||||
<Condition Binding="{Binding
|
||||
roll_schedule,
|
||||
Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_is_defined_converter}}"
|
||||
Value="False" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.default_foreground_dark}" />
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGridTemplateColumn.CellStyle>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<ComboBox
|
||||
ItemsSource="{Binding DataContext.non_options_with_empty, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
|
||||
ItemsSource="{Binding Source={StaticResource NonOptionsWithEmpty}}"
|
||||
ItemTemplate="{StaticResource ExpirationTemplate}"
|
||||
SelectedItem="{Binding roll_schedule, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="2" />
|
||||
Style="{StaticResource ComboBoxCellElement}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
@@ -378,9 +396,7 @@
|
||||
<DataTrigger
|
||||
Binding="{Binding is_roll_target_dirty}"
|
||||
Value="True">
|
||||
<Setter
|
||||
Property="BorderBrush"
|
||||
Value="Red" />
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
@@ -391,14 +407,15 @@
|
||||
Text="{Binding roll_target, Converter={StaticResource DoubleTextConverter}}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="2,0,2,0"
|
||||
ContextMenu="{StaticResource RollTargetContextMenu}" />
|
||||
ContextMenu="{StaticResource RollTargetContextMenu}"
|
||||
Style="{StaticResource TextBlockCellElement}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellEditingTemplate>
|
||||
<DataTemplate>
|
||||
<TextBox
|
||||
Text="{Binding roll_target, Converter={StaticResource DoubleTextConverter}}"
|
||||
Margin="2" />
|
||||
Text="{Binding roll_target, Converter={StaticResource DoubleTextConverter}}"
|
||||
Margin="2" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellEditingTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
@@ -414,9 +431,7 @@
|
||||
<DataTrigger
|
||||
Binding="{Binding is_riskless_rate_dirty}"
|
||||
Value="True">
|
||||
<Setter
|
||||
Property="BorderBrush"
|
||||
Value="Red" />
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
@@ -427,12 +442,14 @@
|
||||
Text="{Binding riskless_rate, Converter={StaticResource RisklessRateConverter}}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="2,0,2,0"
|
||||
ContextMenu="{StaticResource RisklessRateContextMenu}" />
|
||||
ContextMenu="{StaticResource RisklessRateContextMenu}"
|
||||
Style="{StaticResource TextBlockCellElement}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellEditingTemplate>
|
||||
<DataTemplate>
|
||||
<TextBox Text="{Binding riskless_rate, Converter={StaticResource RisklessRateConverter}}" />
|
||||
<TextBox
|
||||
Text="{Binding riskless_rate, Converter={StaticResource RisklessRateConverter}}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellEditingTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
@@ -448,9 +465,7 @@
|
||||
<DataTrigger
|
||||
Binding="{Binding is_settlement_price_dirty}"
|
||||
Value="True">
|
||||
<Setter
|
||||
Property="BorderBrush"
|
||||
Value="Red" />
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
@@ -461,12 +476,14 @@
|
||||
Text="{Binding settlement_price, Converter={StaticResource DoubleTextConverter}}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="2,0,2,0"
|
||||
ContextMenu="{StaticResource SettlementPriceContextMenu}" />
|
||||
ContextMenu="{StaticResource SettlementPriceContextMenu}"
|
||||
Style="{StaticResource TextBlockCellElement}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellEditingTemplate>
|
||||
<DataTemplate>
|
||||
<TextBox Text="{Binding settlement_price, Converter={StaticResource DoubleTextConverter}}" />
|
||||
<TextBox
|
||||
Text="{Binding settlement_price, Converter={StaticResource DoubleTextConverter}}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellEditingTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
@@ -483,9 +500,7 @@
|
||||
<DataTrigger
|
||||
Binding="{Binding is_delta_beta_dirty}"
|
||||
Value="True">
|
||||
<Setter
|
||||
Property="BorderBrush"
|
||||
Value="Red" />
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
@@ -496,12 +511,14 @@
|
||||
Text="{Binding delta_beta, Converter={StaticResource DoubleTextConverter}}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="2,0,2,0"
|
||||
ContextMenu="{StaticResource DeltaBetaContextMenu}" />
|
||||
ContextMenu="{StaticResource DeltaBetaContextMenu}"
|
||||
Style="{StaticResource TextBlockCellElement}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellEditingTemplate>
|
||||
<DataTemplate>
|
||||
<TextBox Text="{Binding delta_beta, Converter={StaticResource DoubleTextConverter}}" />
|
||||
<TextBox
|
||||
Text="{Binding delta_beta, Converter={StaticResource DoubleTextConverter}}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellEditingTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
@@ -518,9 +535,7 @@
|
||||
<DataTrigger
|
||||
Binding="{Binding is_vega_beta_dirty}"
|
||||
Value="True">
|
||||
<Setter
|
||||
Property="BorderBrush"
|
||||
Value="Red" />
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
@@ -528,10 +543,11 @@
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock
|
||||
Text="{Binding vega_beta, Converter={StaticResource DoubleTextConverter}}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="2,0,2,0"
|
||||
ContextMenu="{StaticResource VegaBetaContextMenu}" />
|
||||
Text="{Binding vega_beta, Converter={StaticResource DoubleTextConverter}}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="2,0,2,0"
|
||||
ContextMenu="{StaticResource VegaBetaContextMenu}"
|
||||
Style="{StaticResource TextBlockCellElement}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.CellEditingTemplate>
|
||||
|
||||
+30
-30
@@ -1,10 +1,14 @@
|
||||
namespace mbts.ui.shell {
|
||||
using bts.api;
|
||||
#nullable enable
|
||||
namespace mbts.ui.shell {
|
||||
using bts.api.analytics;
|
||||
|
||||
using mbts.spark;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.converters;
|
||||
using mbts.ui.extensions;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -16,8 +20,8 @@
|
||||
/// Interaction logic for AnalyticsExpirationParametersView.xaml
|
||||
/// </summary>
|
||||
partial class AnalyticsExpirationParametersView : UserControl {
|
||||
IDisposable _context_menu_op;
|
||||
IDisposable _data_context_hooks;
|
||||
IDisposable? _context_menu_op;
|
||||
IDisposable? _data_context_hooks;
|
||||
|
||||
public AnalyticsExpirationParametersView() {
|
||||
InitializeComponent();
|
||||
@@ -31,6 +35,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
public static ExpirationTextConverter expiration_text_converter =>
|
||||
new() {
|
||||
ShowSymbol = true,
|
||||
ShowType = true,
|
||||
MapExp = true
|
||||
};
|
||||
|
||||
public static IValueConverter driver_display_text_converter =>
|
||||
ValueConverter.create<ExpirationDriverImmutable?, string?>(
|
||||
d => d.HasValue ?
|
||||
d.Value.ModeCase switch {
|
||||
ExpirationDriver.ModeOneofCase.Security =>
|
||||
expiration_text_converter.convert(d.Value.Security.to_sec_exp()),
|
||||
ExpirationDriver.ModeOneofCase.TimeWeightedInterpolated => "Calculate",
|
||||
_ => null
|
||||
} :
|
||||
null);
|
||||
|
||||
public static IValueConverter expiration_is_defined_converter =>
|
||||
ValueConverter.create<SecurityExpiration?, bool>(exp =>
|
||||
exp is not null && exp.expiration != default);
|
||||
|
||||
void _grid_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e) {
|
||||
Disposable.dispose(ref _context_menu_op);
|
||||
if (e.OriginalSource is not FrameworkElement el || DataContext is not AnalyticsExpirationParametersVM vm) {
|
||||
@@ -47,30 +73,4 @@
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
class ExpTextConverter : IValueConverter {
|
||||
public ExpTextConverter() {
|
||||
NullOrEmptyText = "None";
|
||||
}
|
||||
|
||||
public bool ShowType { get; set; }
|
||||
public bool ShowSymbol { get; set; }
|
||||
public bool MapExp { get; set; }
|
||||
public string NullOrEmptyText { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
|
||||
var exp = value as SecurityExpiration;
|
||||
if (exp == null || exp.is_empty()) {
|
||||
return NullOrEmptyText;
|
||||
}
|
||||
return ShowSymbol ?
|
||||
SecurityFormatter.format_future(exp.symbol, exp.expiration) :
|
||||
DateFormatter.Format(exp.expiration, DateFormat.MonthCodeLastDigitYear);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
namespace mbts.spark {
|
||||
namespace mbts.spark {
|
||||
using bts.api;
|
||||
using bts.spark;
|
||||
|
||||
using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
@@ -38,11 +41,30 @@
|
||||
|
||||
public void thread_init() {
|
||||
_vm = new AnalyticsExpirationParametersVM(_bus, _init_settings);
|
||||
_view = new AnalyticsExpirationParametersView { DataContext = _vm };
|
||||
|
||||
var auto_copy_rolls_cmd = new SparkCommandCommand(
|
||||
"Auto Copy Rolls", null, _vm.toggle_auto_copy_rolls_cmd);
|
||||
_vm.SubscribeDisposed(_vm.observe_auto_copy_rolls().Subscribe(v =>
|
||||
auto_copy_rolls_cmd.icon = v ? Icons.RecurringSchedule : Icons.RecurringScheduleGray));
|
||||
|
||||
var auto_copy_rates_cmd = new SparkCommandCommand(
|
||||
"Auto Copy Rates", null, _vm.toggle_auto_copy_rates_cmd);
|
||||
_vm.SubscribeDisposed(_vm.observe_auto_copy_rates().Subscribe(v =>
|
||||
auto_copy_rates_cmd.icon = v ? Icons.FinancialGrowth : Icons.FinancialGrowthGray));
|
||||
|
||||
_commands = new() {
|
||||
new SparkCommandCommand("Commit", Icons.Disk, _vm.commit_cmd, new KeyGesture(Key.S, ModifierKeys.Control)),
|
||||
new SparkCommandCommand("Revert", Icons.UndoCircular, _vm.revert_cmd, new KeyGesture(Key.Z, ModifierKeys.Control)),
|
||||
auto_copy_rates_cmd,
|
||||
auto_copy_rolls_cmd,
|
||||
new SparkCommandCommand(
|
||||
"Set Driver to Nearest Exp", null, _vm.set_driver_to_nearest_exp_cmd) {
|
||||
show_in_toolbar = false,
|
||||
show_in_context_menu = true
|
||||
},
|
||||
};
|
||||
|
||||
_view = new AnalyticsExpirationParametersView { DataContext = _vm };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,101 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using bts;
|
||||
using mbts.analytics;
|
||||
using bts.api.analytics;
|
||||
using System.Reactive.Linq;
|
||||
using bts.api;
|
||||
using System.Threading;
|
||||
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
// 1. Reads exp params from the network and publishes
|
||||
// it to the BB
|
||||
// 2. Listens to ExpirationParametersCommitTag and
|
||||
// writes the calls into persistence to save the data
|
||||
public class AnalyticsParametersManager : IDisposable {
|
||||
private readonly ThreadedBlackboard _bb;
|
||||
private AnalyticsService _analytics_service;
|
||||
private List<IDisposable> _disposables = new List<IDisposable>();
|
||||
private IDictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>
|
||||
_data = new Dictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>();
|
||||
private readonly ITag<IEnumerable<AnalyticsExpirationParameters>>
|
||||
_in_bb_exp_params_commit_tag = SparkTags.ExpirationParametersCommitTag;
|
||||
private readonly ITag<SystemContractData> _in_contracts_tag = SparkTags.SystemContractsTag;
|
||||
private readonly ITag<AnalyticsExpirationParametersMap> _out_exp_params_tag =
|
||||
SparkTags.ExpirationParametersInputTag;
|
||||
private HighPerformanceTimer _timer = new HighPerformanceTimer();
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.analytics;
|
||||
|
||||
public AnalyticsParametersManager(ThreadedBlackboard bb,
|
||||
AnalyticsService analytics_server) {
|
||||
_bb = bb;
|
||||
_analytics_service = analytics_server;
|
||||
var exp_params_sub = _analytics_service.subscribei_exp_parameters()
|
||||
.ObserveOn(SynchronizationContext.Current)
|
||||
.Subscribe(_on_exp_parameters);
|
||||
_disposables.Add(exp_params_sub);
|
||||
_bb.subscribe(_in_bb_exp_params_commit_tag);
|
||||
_bb.subscribe(_in_contracts_tag);
|
||||
_bb.data_callback += _on_bb_data;
|
||||
}
|
||||
using mbts.analytics;
|
||||
|
||||
private void _on_bb_data(object tag, object data) {
|
||||
if (_in_contracts_tag.Equals(tag)) {
|
||||
_assemble_and_publish();
|
||||
} else if (_in_bb_exp_params_commit_tag == tag) {
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
|
||||
/// <summary>
|
||||
/// Reads exp params from the network and publishes it to the bus; listens to
|
||||
/// <see cref="SparkTags.ExpirationParametersCommitTag"/> and persists the data
|
||||
/// </summary>
|
||||
public sealed class AnalyticsParametersManager : IDisposable {
|
||||
IDisposable? _dispose;
|
||||
|
||||
public AnalyticsParametersManager(IBus bus, AnalyticsService analytics_service) {
|
||||
var contracts_src = bus.subscribe(SparkTags.SystemContractsTag);
|
||||
|
||||
var exp_params_in_src = analytics_service.subscribei_exp_parameters()
|
||||
.Select(upd => upd.all
|
||||
.SelectMany(ep => ep.ParamList
|
||||
.Select(ep => new AnalyticsExpirationParameters(ep)))
|
||||
.ToDictionary(ep => ep.security));
|
||||
|
||||
var exp_params_out_src = bus.subscribe(SparkTags.ExpirationParametersCommitTag)
|
||||
.Select(eps => eps
|
||||
.Where(ep => ep.security.expiration.Date >= DateTime.Today - TimeSpan.FromDays(1)));
|
||||
|
||||
_dispose = Disposable.Create(
|
||||
exp_params_in_src.CombineLatest(contracts_src)
|
||||
.Select(tup => new AnalyticsExpirationParametersMap(tup.First, tup.Second))
|
||||
.ObserveOn(SynchronizationContext.Current ?? throw new InvalidOperationException())
|
||||
.Subscribe(bus.post_callback(SparkTags.ExpirationParametersInputTag)),
|
||||
exp_params_out_src.Subscribe(save_exp_params));
|
||||
|
||||
void save_exp_params(IEnumerable<AnalyticsExpirationParameters> exp_params) {
|
||||
Func<AnalyticsExpirationParameters, bool> is_unexpired = (p) => {
|
||||
var st = p.driver_security.security_tuple.to_api_sec_tuple();
|
||||
var exp = p.security.expiration;
|
||||
return SecurityExpirationHelper.is_unexpired(st, exp);
|
||||
};
|
||||
exp_params = exp_params.Where(t => is_unexpired(t));
|
||||
// listens to the commit tag and saves it
|
||||
IEnumerable<AnalyticsExpirationParameters> exp_params =
|
||||
data as IEnumerable<AnalyticsExpirationParameters>;
|
||||
exp_params = exp_params.Where(e => e.security.expiration.Date >=
|
||||
DateTime.Now.Date.Subtract(TimeSpan.FromDays(1)));
|
||||
bts.Log.Gen.info(
|
||||
String.Format("AnalyticsParametersManager._on_bb_data received commit count:{0}",
|
||||
exp_params.Count()));
|
||||
ExpirationParameterEntryList to_save = new ExpirationParameterEntryList();
|
||||
Log.Gen.info($"AnalyticsParametersManager received commit req. count:{exp_params.Count()}");
|
||||
var to_save = new ExpirationParameterEntryList();
|
||||
to_save.ParamList.AddRange(exp_params.Select(i => i.to_exp_param_entry()));
|
||||
_timer.start();
|
||||
_analytics_service.set_exp_parameters(to_save);
|
||||
_timer.stop();
|
||||
bts.Log.Gen.info(
|
||||
String.Format("AnalyticsParametersManager saved exp_params count:{0} t:{1} msecs",
|
||||
exp_params.Count(), _timer.lastIntervalTime));
|
||||
Log.Gen.record(
|
||||
null,
|
||||
(dt, elapsed, res) => {
|
||||
var msg = "AnalyticsParametersManager saved exp_params. " +
|
||||
$"count:{exp_params.Count()} t:{elapsed.TotalMilliseconds:0.000}ms";
|
||||
return (LogLevel.Info, msg);
|
||||
},
|
||||
() => analytics_service.set_exp_parameters(to_save));
|
||||
}
|
||||
}
|
||||
|
||||
void _on_exp_parameters(bts.api.core.Update<ExpirationParameterEntryListImmutable, int> update) {
|
||||
_data = new Dictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>();
|
||||
bts.Log.Gen.info(String.Format("AnalyticsParametersManager._on_exp_parameters received count:{0}",
|
||||
update.all.Count()));
|
||||
bts.Log.assert(update.all.Count() == 0 || update.all.Count() == 1);
|
||||
foreach (ExpirationParameterEntryListImmutable l in update.all) {
|
||||
foreach (ExpirationParameterEntryImmutable e in l.ParamList) {
|
||||
AnalyticsExpirationParameters new_entry = new AnalyticsExpirationParameters(e);
|
||||
_data[new_entry.security] = new_entry;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Log.Gen.info($"AnalyticsParametersManager._on_exp_parameters count: {_data.Count}");
|
||||
_assemble_and_publish();
|
||||
// _bb.post(_out_exp_params_tag, new AnalyticsExpirationParametersMap(_data));
|
||||
}
|
||||
|
||||
private void _assemble_and_publish() {
|
||||
if (_data != null) {
|
||||
SystemContractData sc_data = _bb.read_state(_in_contracts_tag);
|
||||
if (sc_data != null) {
|
||||
_bb.post(_out_exp_params_tag, new AnalyticsExpirationParametersMap(_data, sc_data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
public void Dispose() {
|
||||
_bb.data_callback -= _on_bb_data;
|
||||
foreach (IDisposable d in _disposables) {
|
||||
d.Dispose();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
public void Dispose() =>
|
||||
Disposable.dispose(ref _dispose);
|
||||
}
|
||||
}
|
||||
@@ -125,8 +125,8 @@ namespace mbts.spark {
|
||||
if (_is_different(res)) {
|
||||
_last_published = new OptionDriverPriceMap(_sec_tup.security_name, res);
|
||||
var to_fire = new OptionDriverPriceMap(_sec_tup.security_name, res);
|
||||
bts.Log.Gen.info("SingleOptionDriverPricePublisher._compute_and_fire \n" +
|
||||
$"map:{to_fire.log_string()}");
|
||||
// bts.Log.Gen.info("SingleOptionDriverPricePublisher._compute_and_fire \n" +
|
||||
// $"map:{to_fire.log_string()}");
|
||||
_logger.stop_default_timer();
|
||||
_bb.post(SparkTags.OptionDriverBBOTag(_sec_tup.security_name),
|
||||
new OptionDriverPriceMap(_sec_tup.security_name, res));
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using mbts.analytics;
|
||||
using bts;
|
||||
using bts.api.analytics;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using bts.api;
|
||||
using System.Collections;
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.analytics;
|
||||
|
||||
using mbts.analytics;
|
||||
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace mbts.spark {
|
||||
// For a single VolSurface this class
|
||||
// 1. Listents to commmits and calls the service to persist data
|
||||
// 2. Gathers the vol surface input from the nw and publishes it
|
||||
@@ -78,11 +80,8 @@ namespace mbts.spark {
|
||||
_snp_shot_map.Values);
|
||||
}
|
||||
|
||||
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) {
|
||||
byte[] vs_bytes = vs.Volsurface.ToByteArray();
|
||||
return
|
||||
mbts.analytics.VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(vs_bytes);
|
||||
}
|
||||
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) =>
|
||||
ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs.Volsurface.ToByteArray());
|
||||
|
||||
private void _on_bb_data(object tag, object data) {
|
||||
if (_in_bb_committ_tag.Equals(tag)) {
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace mbts.spark {
|
||||
|
||||
public SingleVolSurfaceRequestCalculator(int vs_id, IEnumerable<string> symbols,
|
||||
ThreadedBlackboard threaded_bb) {
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id:{vs_id}");
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id: {vs_id}");
|
||||
_vs_id = vs_id;
|
||||
_symbols = new HashSet<string>(symbols);
|
||||
_bb = threaded_bb;
|
||||
@@ -89,8 +89,8 @@ namespace mbts.spark {
|
||||
effective_req.cascade_up,
|
||||
effective_req.cascade_down);
|
||||
_timer.stop();
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish time:" +
|
||||
$"{_timer.lastIntervalTime} vs_output:{_last_output.log_string()}");
|
||||
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish time: " +
|
||||
$"{_timer.lastIntervalTime}");
|
||||
_bb.post(SparkTags.VolSurfaceCalculationResponseTag(_vs_id),
|
||||
new VolSurfaceCalculationResponse(_last_output, effective_req.request_id));
|
||||
}
|
||||
|
||||
@@ -11,18 +11,22 @@ namespace mbts.analytics {
|
||||
// tags, into IReadOnlyDictionary of symbol vs data publsihed under one tag
|
||||
public class SymbolAggregationPublisher<TData> : IDisposable {
|
||||
private readonly ThreadedBlackboard _bb;
|
||||
private readonly ITag<SystemContractData> _sc_data_tag;
|
||||
private readonly SecurityType _sec_type;
|
||||
Func<string, ITag<TData>> _get_tag;
|
||||
// the tag on which the output will be published
|
||||
ITag<IReadOnlyDictionary<string, TData>> _out_tag;
|
||||
private readonly ITag<SystemContractData> _sc_data_tag;
|
||||
private Dictionary<string, ITag<TData>> _tag_map =
|
||||
new Dictionary<string, ITag<TData>>();
|
||||
private HashSet<object> _obj_tags = new HashSet<object>();
|
||||
private bool _dirty = true;
|
||||
public SymbolAggregationPublisher(
|
||||
ThreadedBlackboard bb,
|
||||
SecurityType sec_type,
|
||||
Func<string, ITag<TData>> get_tag,
|
||||
ITag<IReadOnlyDictionary<string, TData>> out_tag) {
|
||||
_bb = bb;
|
||||
_sec_type = sec_type;
|
||||
_get_tag = get_tag;
|
||||
_out_tag = out_tag;
|
||||
_sc_data_tag = SparkTags.SystemContractsTag;
|
||||
@@ -48,15 +52,20 @@ namespace mbts.analytics {
|
||||
return;
|
||||
}
|
||||
foreach (var st in sc_data.sectup_map) {
|
||||
if (st.security_type != _sec_type) {
|
||||
continue;
|
||||
}
|
||||
// this is not correct since it is assuming symbol/name is
|
||||
// unique across securty_tuples
|
||||
string symbol = st.security_name;
|
||||
if (!_tag_map.ContainsKey(symbol)) {
|
||||
var symbol_tag = _get_tag(symbol);
|
||||
_tag_map.Add(symbol, symbol_tag);
|
||||
_obj_tags.Add(symbol_tag);
|
||||
_bb.subscribe(symbol_tag);
|
||||
_dirty = true;
|
||||
var tag = _get_tag(symbol);
|
||||
if (tag != null) {
|
||||
_tag_map.Add(symbol, tag);
|
||||
_obj_tags.Add(tag);
|
||||
_bb.subscribe(tag);
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ using System.Reactive.Linq;
|
||||
using System.Collections;
|
||||
using mbts.spark;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using Spark.Core.Protobuf;
|
||||
using mbts.ui;
|
||||
// using mbts.bb;
|
||||
|
||||
namespace mbts.spark {
|
||||
@@ -53,6 +55,7 @@ namespace mbts.spark {
|
||||
// 2. Listens to the activation tag (also published by the UI) and
|
||||
// creates the SingleVolSurfaceManager for the VS
|
||||
public class VolSurfaceBusManager : IDisposable {
|
||||
private List<IDisposable> _disps = new List<IDisposable>();
|
||||
private ThreadedBlackboard _bb;
|
||||
private bts.api.analytics.AnalyticsService _analytics_service;
|
||||
// in tags
|
||||
@@ -74,10 +77,11 @@ namespace mbts.spark {
|
||||
private HighPerformanceTimer _timer = new HighPerformanceTimer();
|
||||
|
||||
public VolSurfaceBusManager(bts.api.IBus bus,
|
||||
bts.api.analytics.AnalyticsService analytics_service) {
|
||||
bts.api.analytics.AnalyticsService analytics_service,
|
||||
bts.api.orderman.OrderService order_service) {
|
||||
bts.Log.Ui.info("VSBusManager cons tid:{VolSurfaceTroubleshootingFunctions.tid()}");
|
||||
_bus = bus;
|
||||
_bb = new ThreadedBlackboard(bus);
|
||||
_bb = new ThreadedBlackboard("AW2", bus);
|
||||
_analytics_service = analytics_service;
|
||||
// subs to bb
|
||||
_bb.subscribe(_in_scdata_tag);
|
||||
@@ -96,48 +100,121 @@ namespace mbts.spark {
|
||||
.Subscribe(_on_vs_usage_update);
|
||||
_subs.Add(vs_sub);
|
||||
_subs.Add(vs_usage_sub);
|
||||
_subs.Add(new AnalyticsParametersManager(_bb, _analytics_service));
|
||||
_subs.Add(new AnalyticsParametersManager(bus, _analytics_service));
|
||||
_subs.Add(new ResourceAllocator(bus, _bb));
|
||||
_subs.Add(new SymbolAggregationPublisher<OptionDriverPriceMap>(
|
||||
_bb, (sym) => SparkTags.OptionDriverBBOTag(sym),
|
||||
_bb, SecurityType.Option, sym => SparkTags.OptionDriverBBOTag(sym),
|
||||
SparkTags.AllOptionDriverBBOTag));
|
||||
_subs.Add(new SymbolAggregationPublisher<OptionTheoInterpolationData>(
|
||||
_bb, (sym) => SparkTags.SymbolInterpGreeksTag(sym),
|
||||
_bb, SecurityType.Option, sym => SparkTags.SymbolInterpGreeksTag(sym),
|
||||
SparkTags.AllInterpGreeks));
|
||||
_subs.Add(new SymbolAggregationPublisher<ExpStrikeKeyedData<TheoPoint>>(
|
||||
_bb, SecurityType.Option, sym => SparkTags.TC2Tags.LiveTheosTag(sym),
|
||||
SparkTags.TC2Tags.AllLiveTheosTag));
|
||||
_subs.Add(new LiveTheoPublisher(_bb));
|
||||
_subs.Add(new InterpTheosServerPublisher(_bb, order_service));
|
||||
_subs.Add(new VolSurfaceInterpGreeksMultiplexer(_bb));
|
||||
//_subs.Add(new AnalyticsServiceTester(_bb));
|
||||
// TODO: temporatily publish values
|
||||
VolSurfaceUsageList ulist = new VolSurfaceUsageList();
|
||||
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
|
||||
VsId = 6,
|
||||
SecTup = new bts.api.SecurityTuple() {
|
||||
Type = SecurityType.Option,
|
||||
Venue = VolSurfaceTemp.get_default_venue(SecurityType.Option, "BTC"),
|
||||
Symbol = "BTC"
|
||||
// usage
|
||||
var list_sub = _bus.subscribe(SparkTags.VolSurfaceListTag).OnDispatcher().Subscribe(t => {
|
||||
VolSurfaceUsageList ulist = new VolSurfaceUsageList();
|
||||
IDictionary<string, int> name_to_ids = new Dictionary<string, int>();
|
||||
foreach (var kv in t) {
|
||||
name_to_ids[kv.Value] = kv.Key;
|
||||
}
|
||||
});
|
||||
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
|
||||
VsId = 7,
|
||||
SecTup = new bts.api.SecurityTuple() {
|
||||
Type = SecurityType.Option,
|
||||
Venue = VolSurfaceTemp.get_default_venue(SecurityType.Option, "ETH"),
|
||||
Symbol = "ETH"
|
||||
Log.Ui.info($"VolSurfaceUsageList name_to_ids count: {name_to_ids.Count}");
|
||||
var vs_usage = mbts.config.Configuration.get<bts.config.toggles.VolSurfaceUsage>();
|
||||
Log.Ui.info($"VolSurfaceUsageList vs_usage acount: {vs_usage.vol_surface_usage.Count}");
|
||||
foreach (var u in vs_usage.vol_surface_usage) {
|
||||
string option_name = u.option_name;
|
||||
string vs_name = u.vs_name;
|
||||
int vs_key;
|
||||
if (name_to_ids.TryGetValue(vs_name, out vs_key)) {
|
||||
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
|
||||
VsId = vs_key,
|
||||
SecTup = new bts.api.SecurityTuple {
|
||||
Type = SecurityType.Option,
|
||||
Venue = Venue.Deribit,
|
||||
Symbol = option_name
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Log.Gen.error($"Could not find vol surface with name: {vs_name}");
|
||||
}
|
||||
}
|
||||
var list_imm = new VolSurfaceUsageListImmutable(ulist);
|
||||
Log.Ui.info(list_imm.log_string());
|
||||
_bb.post(SparkTags.VolSurfaceUsageTag, list_imm);
|
||||
_spin_vss(list_imm);
|
||||
});
|
||||
_bb.post(SparkTags.VolSurfaceUsageTag, new VolSurfaceUsageListImmutable(ulist));
|
||||
_disps.Add(list_sub);
|
||||
// f(contract keyed theos, securities) -> id keyed theos
|
||||
// (so the newer UI controls can access theos vis sec keys)
|
||||
var theo_sub =
|
||||
_bus.subscribe(SparkTags.TC2Tags.AllLiveTheosTag)
|
||||
.CombineLatest(bus.subscribe(SparkTags.SystemContractsTag),
|
||||
(theos, sc_data) => (theos, sc_data)).Subscribe(
|
||||
tup => {
|
||||
var keyed_theos = _assemble_keyed_theos(tup.sc_data, tup.theos);
|
||||
_bus.post(SparkTags.KeyedTheos, keyed_theos);
|
||||
}
|
||||
);
|
||||
_disps.Add(theo_sub);
|
||||
}
|
||||
|
||||
static IReadOnlyDictionary<uint, VolSurfaceTheoPoint> _assemble_keyed_theos(
|
||||
SystemContractData sc_data,
|
||||
IReadOnlyDictionary<string, ExpStrikeKeyedData<TheoPoint>> theos) {
|
||||
if (sc_data is null || theos is null) {
|
||||
return new Dictionary<uint, VolSurfaceTheoPoint>(0);
|
||||
}
|
||||
|
||||
HighPerformanceTimer timer = new HighPerformanceTimer();
|
||||
timer.start();
|
||||
Dictionary<uint, VolSurfaceTheoPoint> rv = new Dictionary<uint, VolSurfaceTheoPoint>();
|
||||
foreach (var kv in theos) {
|
||||
var symbol = kv.Key;
|
||||
ExpStrikeKeyedData<TheoPoint> sym_theos = kv.Value;
|
||||
if (sym_theos == null)
|
||||
continue;
|
||||
foreach (var s_kv in sym_theos.get_data_linearly()) {
|
||||
DateTime exp = s_kv.first;
|
||||
double strike = s_kv.second;
|
||||
TheoPoint tp = s_kv.third;
|
||||
// TODO: fix exchange later
|
||||
Tuple<uint?, uint?> keys =
|
||||
sc_data.get_option_sec_id(Venue.Deribit, symbol, exp, strike);
|
||||
if (keys != null) {
|
||||
var c_key = keys.Item1;
|
||||
var p_key = keys.Item2;
|
||||
if (c_key.HasValue) {
|
||||
rv[c_key.Value] = new VolSurfaceTheoPoint(tp, true);
|
||||
}
|
||||
if (p_key.HasValue) {
|
||||
rv[p_key.Value] = new VolSurfaceTheoPoint(tp, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
timer.stop();
|
||||
Log.Gen.info($"VolSurfaceBusManager keyed theos count: {rv.Count} " +
|
||||
$"time: {timer.lastIntervalTime}");
|
||||
return rv;
|
||||
}
|
||||
|
||||
public ThreadedBlackboard bb() {
|
||||
return _bb;
|
||||
}
|
||||
|
||||
void _spin_vss(VolSurfaceUsageListImmutable ulist) {
|
||||
foreach (var u in ulist.UsageList) {
|
||||
var vs_id = u.VsId;
|
||||
_bb.post(SparkTags.VolSurfaceActiveUITag(vs_id), true);
|
||||
}
|
||||
}
|
||||
|
||||
void _on_vs_usage_update(Update<VolSurfaceUsageListImmutable, int> update) {
|
||||
// TODO
|
||||
return;
|
||||
// int vs_count = update.all.Count();
|
||||
// Log.Gen.info($"VSBusManager._on_vs_usage_update " +
|
||||
// $"tid:{Thread.CurrentThread.ManagedThreadId} count:{update.all.Count()}");
|
||||
// Log.assert(vs_count <= 1);
|
||||
// if (update.all.TryGetSingle(out var to_write)) {
|
||||
// _bb.post(SparkTags.VolSurfaceUsageTag, to_write);
|
||||
// }
|
||||
}
|
||||
|
||||
void _on_vss(bts.api.core.Update<VolSurfaceEntryImmutable, UInt64> update) {
|
||||
@@ -172,7 +249,7 @@ namespace mbts.spark {
|
||||
// callback
|
||||
mbts.analytics.VolSurfaceSettings vs_settings = data as mbts.analytics.VolSurfaceSettings;
|
||||
bts.Log.Gen.info(String.Format("VSBusManager._on_bb_update received vs creation tag vs:{0}",
|
||||
VolSurfaceUtilityFunctions.serialize_proto_to_text(vs_settings)));
|
||||
ProtobufSerializationHelper.serialize_to_string(vs_settings)));
|
||||
_waiting_creations.Enqueue(vs_settings);
|
||||
} else if (_in_bb_delete_tag.Equals(tag)) {
|
||||
int vs_id = (int)data;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
namespace mbts.analytics {
|
||||
using mbts.spark;
|
||||
|
||||
// TheoPoint (from edge) has both calls and puts in the same structure.
|
||||
// This shoudl dis-entangle that
|
||||
public class VolSurfaceTheoPoint {
|
||||
public readonly double theo = double.NaN;
|
||||
public readonly double delta = double.NaN;
|
||||
public readonly double driver = double.NaN;
|
||||
public VolSurfaceTheoPoint(TheoPoint tp, bool is_call) {
|
||||
if (tp != null) {
|
||||
theo = is_call ? tp.fwd_normalized_call : tp.fwd_normalized_put;
|
||||
delta = is_call ? tp.cdelta : tp.pdelta;
|
||||
driver = tp.driver;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
using mbts.user.settings;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class VolSurfaceDisplayGridColumn : IEquatable<VolSurfaceDisplayGridColumn> {
|
||||
public readonly Func<object, string> format;
|
||||
@@ -18,16 +19,19 @@
|
||||
VolSurfaceColumnSettings settings,
|
||||
Func<object, string> format = null,
|
||||
Func<string, object> parse = null,
|
||||
Func<object, bool, object> tick_move = null) {
|
||||
Func<object, bool, object> tick_move = null,
|
||||
IEqualityComparer<object> comparer = null) {
|
||||
this.settings = settings;
|
||||
this.format = format ?? (v => v?.ToString() ?? string.Empty);
|
||||
this.parse = parse ?? (v => v);
|
||||
this.tick_move = tick_move ?? ((v, is_up) => v);
|
||||
this.comparer = comparer ?? EqualityComparer<object>.Default;
|
||||
}
|
||||
|
||||
public string unique_col_name => settings.id;
|
||||
public string display_name => settings.display_name;
|
||||
public string group => settings.group;
|
||||
public IEqualityComparer<object> comparer { get; }
|
||||
|
||||
internal VolSurfaceColumnType type => settings.type;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
using mbts.user.settings;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
class VolSurfaceDisplayUtilities {
|
||||
public static TickDisplaySettings default_tick_display =>
|
||||
@@ -18,6 +19,10 @@
|
||||
default_tick_display.with(display_multiplier: 100);
|
||||
|
||||
public static double parse_double(object obj) {
|
||||
if (obj is null) {
|
||||
Log.Gen.warn("parse_double received null input (will return nan and continue)");
|
||||
return double.NaN;
|
||||
}
|
||||
Log.assert(obj is double);
|
||||
obj = obj ?? Double.NaN;
|
||||
double rv = obj is Double ? (double)obj : (Double.TryParse(obj.ToString(), out rv) ? rv : Double.NaN);
|
||||
@@ -49,9 +54,31 @@
|
||||
}
|
||||
|
||||
public static Func<object, bool, object> get_double_tickmove(TickFactors tick_factors, int tick_move) =>
|
||||
(data, is_up) => data is double d_data ?
|
||||
tick_factors.tick(d_data, is_up ? tick_move : -tick_move) :
|
||||
data;
|
||||
(data, is_up) => {
|
||||
if (data is not double dbl) {
|
||||
return data;
|
||||
}
|
||||
if (dbl.is_nan()) {
|
||||
return 0D;
|
||||
}
|
||||
return tick_factors.tick(dbl, is_up ? tick_move : -tick_move);
|
||||
};
|
||||
|
||||
public static IEqualityComparer<double> get_double_comparer(
|
||||
TickFactors tick_factors = null, double display_mult = double.NaN) {
|
||||
if (tick_factors is null) {
|
||||
return new TickFactors(10^7, 1).tick_equality_comparer();
|
||||
}
|
||||
// This equality comparer is used to compare actual values (not multiplied by
|
||||
// 'display_mult'), while the TickFactors are used to format the display value (multiplied
|
||||
// by 'display_mult'). Multiply the tick base by 'display_mult' so the equality comparison
|
||||
// is done with the correct number of decimal places.
|
||||
if (display_mult > 0 && Math.Log10(display_mult).is_int()) {
|
||||
tick_factors = tick_factors.with(
|
||||
tick_base: tick_factors.tick_base * display_mult);
|
||||
}
|
||||
return tick_factors.tick_equality_comparer();
|
||||
}
|
||||
|
||||
public static VolSurfaceDisplayGridColumn get_double_output_col(
|
||||
string group,
|
||||
@@ -113,7 +140,10 @@
|
||||
col_config,
|
||||
format: get_double_tostring(col_config.tick_factors, col_config.tick_display),
|
||||
parse: get_parse_double(col_config.tick_factors, col_config.tick_display),
|
||||
tick_move: get_double_tickmove(col_config.tick_factors, col_config.tick_move));
|
||||
tick_move: get_double_tickmove(col_config.tick_factors, col_config.tick_move),
|
||||
comparer: get_double_comparer(
|
||||
col_config.tick_factors, col_config.tick_display.display_multiplier)
|
||||
.cast<double, object>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using mbts.analytics;
|
||||
using bts.api;
|
||||
using bts.collections;
|
||||
using System.Linq;
|
||||
using bts.api.orderman;
|
||||
using bts;
|
||||
|
||||
namespace mbts.spark {
|
||||
// Listens to the interp theos, decorates the data
|
||||
// and sends them over to the sparkd server
|
||||
public class InterpTheosServerPublisher : IDisposable {
|
||||
private readonly ThreadedBlackboard _bb;
|
||||
private readonly bts.api.orderman.OrderService _order_service;
|
||||
private HighPerformanceTimer _timer = new HighPerformanceTimer();
|
||||
|
||||
public InterpTheosServerPublisher(ThreadedBlackboard bb,
|
||||
bts.api.orderman.OrderService order_service) {
|
||||
bts.Log.Ui.info(
|
||||
$"InterpTheosServerPublisher cons tid:{VolSurfaceTroubleshootingFunctions.tid()}");
|
||||
_bb = bb;
|
||||
_order_service = order_service;
|
||||
_bb.subscribe(SparkTags.AllInterpGreeks);
|
||||
_bb.subscribe(SparkTags.SystemContractsTag);
|
||||
_bb.data_callback += _on_data;
|
||||
}
|
||||
|
||||
private void _on_data(object tag, object data) {
|
||||
if (tag.Equals(SparkTags.SystemContractsTag) ||
|
||||
tag.Equals(SparkTags.AllInterpGreeks)) {
|
||||
_publish_data();
|
||||
}
|
||||
}
|
||||
|
||||
private static IDictionary<UInt32, DriverMD> _get_drivers(
|
||||
IReadOnlyDictionary<string, OptionDriverPriceMap> driver_map,
|
||||
SystemContractData sc_data) {
|
||||
var rv = new Dictionary<UInt32, DriverMD>();
|
||||
foreach (var kv in driver_map) {
|
||||
rv.AddRange(
|
||||
SecurityNormalizer.normalize_drivers(kv.Value, sc_data).ToArray());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
private static IEnumerable<Tuple<SecurityImmutable, TheoPoint>> _get_theos(
|
||||
IReadOnlyDictionary<string, OptionTheoInterpolationData> theo_data,
|
||||
SystemContractData sc_data) {
|
||||
var rv = new List<Tuple<SecurityImmutable, TheoPoint>>();
|
||||
foreach (var kv in theo_data) {
|
||||
rv.AddRange(
|
||||
SecurityNormalizer.normalize_interp_theos(kv.Value, sc_data));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
private void _publish_data() {
|
||||
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag, null);
|
||||
IReadOnlyDictionary<string, OptionTheoInterpolationData> all_theos =
|
||||
_bb.read_state(SparkTags.AllInterpGreeks, null);
|
||||
IReadOnlyDictionary<string, OptionDriverPriceMap> all_drivers =
|
||||
_bb.read_state(SparkTags.AllOptionDriverBBOTag, null);
|
||||
if (sc_data == null || all_theos == null || all_drivers == null)
|
||||
return;
|
||||
_timer.start();
|
||||
IDictionary<UInt32, DriverMD> driver_map = _get_drivers(all_drivers, sc_data);
|
||||
IEnumerable<Tuple<SecurityImmutable, TheoPoint>> theo_map = _get_theos(all_theos, sc_data);
|
||||
// assemble it together and send it to the server
|
||||
var ptp_list = new List<bts.api.orderman.PrecomputedTheoPoint>();
|
||||
foreach (var tup in theo_map) {
|
||||
SecurityImmutable sec = tup.Item1;
|
||||
TheoPoint tp = tup.Item2;
|
||||
bool is_call = sec.Option.CallPut == PutOrCall.Call;
|
||||
var sec_id = sec.Id;
|
||||
DriverMD dmd = null;
|
||||
driver_map.TryGetValue(sec_id, out dmd);
|
||||
PrecomputedTheoPoint ptp = new PrecomputedTheoPoint();
|
||||
ptp.SecId = sec_id;
|
||||
ptp.Driver = tp.driver;
|
||||
ptp.DriverSecId = dmd != null && dmd.driver_security.HasValue ?
|
||||
dmd.driver_security.Value.Id : 0;
|
||||
ptp.Theo = is_call ? tp.call : tp.put;
|
||||
ptp.Delta = is_call ? tp.cdelta : tp.pdelta;
|
||||
ptp.Gamma = is_call ? tp.cgamma : tp.pgamma;
|
||||
ptp.Vega = is_call ? tp.cvega : tp.pvega;
|
||||
ptp.Theta = is_call ? tp.c_theta : tp.p_theta;
|
||||
ptp.Rho = Double.NaN;
|
||||
ptp_list.Add(ptp);
|
||||
}
|
||||
bts.api.orderman.PrecomputedTheos server_theos = new PrecomputedTheos();
|
||||
server_theos.Theos.AddRange(ptp_list);
|
||||
_timer.stop();
|
||||
var comp_time = _timer.lastIntervalTime;
|
||||
_timer.start();
|
||||
_order_service.set_precomputed_theos(server_theos);
|
||||
_timer.stop();
|
||||
var pub_time = _timer.lastIntervalTime;
|
||||
bts.Log.Gen.info($"InterpTheosServerPublisher._publish_data " +
|
||||
$"size: {server_theos.Theos.Count} comp_time: {comp_time} msecs " +
|
||||
$"pub_time: {pub_time}");
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
_bb.data_callback -= _on_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,10 @@ using System.Collections.Generic;
|
||||
using mbts.analytics;
|
||||
using bts.api;
|
||||
using mbts.ui;
|
||||
using MathNet.Numerics.Providers.FourierTransform;
|
||||
using BCG;
|
||||
using System.Windows.Automation;
|
||||
using bts.collections;
|
||||
|
||||
namespace mbts.spark {
|
||||
// Publishes theos for all options (on the side, also publishes the theos for TC2)
|
||||
@@ -15,12 +19,15 @@ namespace mbts.spark {
|
||||
private readonly HighPerformanceTimer _timer = new HighPerformanceTimer();
|
||||
private readonly PerfStatsLogger _logger = new PerfStatsLogger(50, 100);
|
||||
private readonly string _log_id = "LiveTheoPublisher";
|
||||
private DateTime _last_future_theos_published = DateTime.MinValue;
|
||||
private TimeSpan _futures_theos_publish_period = TimeSpan.FromMilliseconds(300);
|
||||
|
||||
public LiveTheoPublisher(ThreadedBlackboard bb) {
|
||||
_bb = bb;
|
||||
_bb.subscribe(_greeks_tag);
|
||||
_bb.subscribe(_drivers_tag);
|
||||
_bb.data_callback += _on_data;
|
||||
_bb.timer_callback += _on_timer;
|
||||
_interp_and_publish();
|
||||
}
|
||||
|
||||
@@ -31,6 +38,10 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
private void _on_timer() {
|
||||
_publish_future_theos();
|
||||
}
|
||||
|
||||
private void _log_interpgreeks(
|
||||
IReadOnlyDictionary<string, OptionTheoInterpolationData> interp_greeks) {
|
||||
string log_msg = String.Empty;
|
||||
@@ -59,19 +70,14 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
private void _log_theos(SystemContractData sc_data,
|
||||
IReadOnlyDictionary<uint, GreeksTuple> greeks_map,
|
||||
DateTime? exp_filt = null) {
|
||||
IReadOnlyDictionary<uint, GreeksTuple> greeks_map) {
|
||||
string rv = "LiveTheosPublisher data: ";
|
||||
foreach (var kv in greeks_map) {
|
||||
var id = kv.Key;
|
||||
var g_tup = kv.Value;
|
||||
if (sc_data.sec_md_map.TryGetValue(id, out var smd)) {
|
||||
if (exp_filt == null ||
|
||||
(smd.security.security_type() == SecurityType.Option &&
|
||||
smd.security.Option.expiration_date().Equals(exp_filt.Value))) {
|
||||
string sec_str = smd.ToString();
|
||||
rv += "\n" + $"id: {id} sec: {sec_str} greeks: {g_tup}";
|
||||
}
|
||||
string sec_str = smd.ToString();
|
||||
rv += "\n" + $"id: {id} sec: {sec_str} greeks: {g_tup}";
|
||||
}
|
||||
}
|
||||
bts.Log.Gen.info(rv);
|
||||
@@ -125,36 +131,93 @@ namespace mbts.spark {
|
||||
return;
|
||||
}
|
||||
var k_theos = new Dictionary<SecurityStrike, TheoPoint>();
|
||||
// option spreads
|
||||
foreach (var kv in sc_data.strike_map) {
|
||||
foreach (SecurityStrike k in kv.Value) {
|
||||
var cp_id = k.call_put_id;
|
||||
var (call_id, put_id) = k.call_put_id;
|
||||
var driver = _get_option_driver(driver_map, k);
|
||||
var tp = _interp_theo(interp_greeks, k, driver.get_driver());
|
||||
k_theos[k] = tp;
|
||||
// put it in the output map
|
||||
if (cp_id.Item1.HasValue) {
|
||||
res.Add(cp_id.Item1.Value,
|
||||
if (call_id.HasValue) {
|
||||
var normalized_theo = VolSurfaceCoreFunctions.normalize_theo(tp.call, tp.driver);
|
||||
res.Add(call_id.Value,
|
||||
new GreeksTuple(tp.vol, tp.driver, tp.call, tp.cdelta, tp.cgamma,
|
||||
tp.cvega, tp.c_theta, Double.NaN));
|
||||
tp.cvega, tp.c_theta, Double.NaN, normalized_theo));
|
||||
}
|
||||
if (cp_id.Item2.HasValue) {
|
||||
res.Add(cp_id.Item2.Value,
|
||||
if (put_id.HasValue) {
|
||||
var normalized_theo = VolSurfaceCoreFunctions.normalize_theo(tp.put, tp.driver);
|
||||
res.Add(put_id.Value,
|
||||
new GreeksTuple(tp.vol, tp.driver, tp.put, tp.pdelta, tp.pgamma,
|
||||
tp.pvega, tp.p_theta, Double.NaN));
|
||||
tp.pvega, tp.p_theta, Double.NaN, normalized_theo));
|
||||
}
|
||||
}
|
||||
}
|
||||
// futures
|
||||
var future_theos = _get_future_theos();
|
||||
res.AddRange(future_theos);
|
||||
// spreads, all option and future non tied spreads
|
||||
foreach (var spr in sc_data.spreads) {
|
||||
GreeksTuple gtup = StatelessSpreadCalculator.compute_non_tied_spread(spr.security, res);
|
||||
res.Add(spr.security.Id, gtup);
|
||||
}
|
||||
// copy and publish
|
||||
IReadOnlyDictionary<uint, GreeksTuple> res_ro = res;
|
||||
bts.Log.Gen.info($"LiveTheoPublisher._interp_and_publish posting " +
|
||||
$"count: {res_ro.Count}");
|
||||
$"count: {res_ro.Count}");
|
||||
_timer.stop();
|
||||
_logger.log(_log_id, _log_id, _timer.lastIntervalTime);
|
||||
_bb.post(SparkTags.Greeks, res_ro);
|
||||
// oh and those TC2 theos for comptability
|
||||
_publish_tc2_theos(k_theos);
|
||||
}
|
||||
|
||||
// If we do any rolls like SP for futures, it will be here
|
||||
IDictionary<UInt32, GreeksTuple> _get_future_theos() {
|
||||
var rv = new Dictionary<UInt32, GreeksTuple>();
|
||||
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag);
|
||||
if (sc_data == null)
|
||||
return rv;
|
||||
foreach (var kv in sc_data.exp_map) {
|
||||
var id = kv.Value;
|
||||
SecurityMD sec_md;
|
||||
if (sc_data.sec_md_map.TryGetValue(id, out sec_md)) {
|
||||
if (sec_md.security.HasFuture) {
|
||||
SecurityExpiration exp = kv.Key;
|
||||
double pr = sec_md.md.fixing_price;
|
||||
rv.Add(sec_md.security.Id,
|
||||
new GreeksTuple(0, pr, pr, 1, 0, 0, 0, 0, pr));
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// recomputes and publishes them periodicially
|
||||
void _publish_future_theos() {
|
||||
if (DateTime.Now - _last_future_theos_published < _futures_theos_publish_period)
|
||||
return;
|
||||
_last_future_theos_published = DateTime.Now;
|
||||
var rv = new Dictionary<SecurityExpiration, FutureTheoStructure>();
|
||||
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag);
|
||||
if (sc_data == null)
|
||||
return;
|
||||
foreach (var kv in sc_data.exp_map) {
|
||||
var id = kv.Value;
|
||||
SecurityMD sec_md;
|
||||
if (sc_data.sec_md_map.TryGetValue(id, out sec_md)) {
|
||||
if (sec_md.security.HasFuture) {
|
||||
SecurityExpiration exp = kv.Key;
|
||||
double pr = sec_md.md.fixing_price;
|
||||
rv.Add(exp, new FutureTheoStructure(exp.expiration, pr, pr, 1, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
_bb.post(SparkTags.TC2Tags.LiveFutureTheosTag, rv);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
_bb.data_callback -= _on_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace mbts.spark {
|
||||
var exp = kv.Key;
|
||||
if (!temp.ContainsKey(kv.Key)) {
|
||||
temp.Add(kv.Key,
|
||||
new AnalyticsExpirationParameters(exp, empty, empty, empty, 0, 0, 0, 0, 0));
|
||||
new AnalyticsExpirationParameters(exp, null, empty, empty, 0, 0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
exp_map = temp;
|
||||
|
||||
@@ -1,58 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using mbts.analytics;
|
||||
using bts.api;
|
||||
using bts.api.persistence;
|
||||
using System.Linq;
|
||||
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using bts.api;
|
||||
|
||||
using mbts.analytics;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
// All driver prices (along with some more info) for an option symbol
|
||||
public class OptionDriverPriceMap {
|
||||
public readonly String option_symbol = null;
|
||||
public readonly IDictionary<SecurityExpiration, DriverMD> exp_price_map = null;
|
||||
public readonly string option_symbol;
|
||||
public readonly IDictionary<SecurityExpiration, DriverMD> exp_price_map;
|
||||
|
||||
Dictionary<SecurityExpiration, DriverMD>? _unexpired_exp_price_map_backing;
|
||||
|
||||
public OptionDriverPriceMap(
|
||||
string option_symbol_a,
|
||||
IDictionary<SecurityExpiration, DriverMD> exp_price_map_a) {
|
||||
option_symbol = option_symbol_a;
|
||||
exp_price_map = exp_price_map_a;
|
||||
}
|
||||
public IDictionary<SecurityExpiration, DriverMD> unexpired_exp_price_map {
|
||||
get {
|
||||
return exp_price_map.Where(
|
||||
kv => kv.Key.expiration >= DateTime.Now.Date).ToDictionary(
|
||||
kv => kv.Key, kv => kv.Value);
|
||||
}
|
||||
string option_symbol, IDictionary<SecurityExpiration, DriverMD> exp_price_map) {
|
||||
this.option_symbol = option_symbol;
|
||||
this.exp_price_map = exp_price_map;
|
||||
}
|
||||
|
||||
public IDictionary<SecurityExpiration, DriverMD> unexpired_exp_price_map =>
|
||||
_unexpired_exp_price_map_backing ??=
|
||||
exp_price_map.Where(kv => kv.Key.expiration >= DateTime.Now.Date).ToDictionary();
|
||||
|
||||
// this is the BS needed because of ignoring exchange
|
||||
public DriverMD get_driver_md(DateTime exp) {
|
||||
foreach (var kv in exp_price_map) {
|
||||
if (kv.Key.expiration == exp) {
|
||||
return kv.Value;
|
||||
}
|
||||
}
|
||||
return DriverMD.empty;
|
||||
}
|
||||
public DriverMD get_driver_md(SecurityExpiration exp) {
|
||||
if (exp_price_map.TryGetValue(exp, out var d))
|
||||
return d;
|
||||
return DriverMD.empty;
|
||||
}
|
||||
public DriverMD get_driver_md(DateTime exp) =>
|
||||
exp_price_map.FirstOrDefault(kv => kv.Key.expiration == exp).Value ?? DriverMD.empty;
|
||||
|
||||
public DriverMD get_driver_md(SecurityExpiration exp) =>
|
||||
exp_price_map.GetValueOrDefault(exp) ?? DriverMD.empty;
|
||||
|
||||
public static IDictionary<VolSurfaceExpiration, DriverMD> get_vs_price_map(
|
||||
IReadOnlyDictionary<string, OptionDriverPriceMap> all_sym_map,
|
||||
Func<string, bool> sym_filter = null) {
|
||||
var rv = new Dictionary<VolSurfaceExpiration, DriverMD>();
|
||||
if (all_sym_map != null)
|
||||
foreach (var kv in all_sym_map) {
|
||||
string sym = kv.Key;
|
||||
OptionDriverPriceMap sym_map = kv.Value;
|
||||
if (sym_filter == null || sym_filter(sym)) {
|
||||
foreach (var kv_int in sym_map.exp_price_map) {
|
||||
rv[new VolSurfaceExpiration(kv_int.Key)] = kv_int.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
Func<string, bool>? sym_filter = null
|
||||
) {
|
||||
sym_filter ??= _ => true;
|
||||
return all_sym_map.SafeWhere(kv => kv.Value is not null && sym_filter(kv.Key))
|
||||
.SelectMany(kv => kv.Value.exp_price_map)
|
||||
.ToDictionaryCrushed(kv => kv.Key.to_vs_exp(), kv => kv.Value);
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<SecurityExpiration, DriverMD> get_price_map() {
|
||||
return new Dictionary<SecurityExpiration, DriverMD>(exp_price_map);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
namespace mbts.spark {
|
||||
using bts.api;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
// A lot of options data (migrated from edge) is not normalized
|
||||
// on the sec_id, but rather on a combination of symbol, exp, strike.
|
||||
// Additionally the exchange is missing. This class serves as that
|
||||
// one since point to resolve that.
|
||||
// (Over time we will normalize all the data and this wont be needed)
|
||||
public static class SecurityNormalizer {
|
||||
// f(option_exp:driver_md) -> (sec_id:driver_md)
|
||||
|
||||
public static IDictionary<UInt32, DriverMD> normalize_drivers(
|
||||
OptionDriverPriceMap driver_map, SystemContractData sc_data) {
|
||||
if (driver_map is null) {
|
||||
return new Dictionary<uint, DriverMD>(0);
|
||||
}
|
||||
Dictionary<UInt32, DriverMD> rv = new Dictionary<uint, DriverMD>();
|
||||
foreach (var kv in driver_map.get_price_map()) {
|
||||
var exp = kv.Key;
|
||||
var dmd = kv.Value;
|
||||
IEnumerable<SecurityMD> exp_secs = sc_data.get_securities(
|
||||
(sec_md) => {
|
||||
var s = sec_md.security;
|
||||
return s.security_type() == SecurityType.Option &&
|
||||
s.Symbol == driver_map.option_symbol &&
|
||||
s.earliest_expiration() == exp.expiration;
|
||||
}
|
||||
);
|
||||
foreach (var sec_md in exp_secs) {
|
||||
rv.Add(sec_md.security.Id, kv.Value);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public static IEnumerable<Tuple<SecurityImmutable, TheoPoint>> normalize_interp_theos(
|
||||
OptionTheoInterpolationData symbol_theos, SystemContractData sc_data) {
|
||||
if (symbol_theos is null) {
|
||||
return Enumerable.Empty<Tuple<SecurityImmutable, TheoPoint>>();
|
||||
}
|
||||
var rv = new List<Tuple<SecurityImmutable, TheoPoint>>();
|
||||
foreach (DateTime exp in symbol_theos.get_expirations()) {
|
||||
Dictionary<double, Dictionary<double, TheoPoint>> exp_data =
|
||||
symbol_theos.get_expiration_data(exp);
|
||||
// exp_data is driver vs strike vs TP
|
||||
foreach (var exp_kv in exp_data) {
|
||||
foreach (var k_kv in exp_kv.Value) {
|
||||
double strike = k_kv.Key;
|
||||
TheoPoint tp = k_kv.Value;
|
||||
IEnumerable<SecurityMD> calls = sc_data.get_options(
|
||||
null, symbol_theos.symbol, exp, strike, PutOrCall.Call);
|
||||
IEnumerable<SecurityMD> puts = sc_data.get_options(
|
||||
null, symbol_theos.symbol, exp, strike, PutOrCall.Put);
|
||||
foreach (SecurityMD sec_md in calls) {
|
||||
rv.Add(Tuple.Create(sec_md.security, tp));
|
||||
}
|
||||
foreach (SecurityMD sec_md in puts) {
|
||||
rv.Add(Tuple.Create(sec_md.security, tp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -107,6 +108,22 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public SecurityImmutable? get_option_contract(
|
||||
Venue venue, string symbol, DateTime exp, double strike, PutOrCall cp) {
|
||||
var k_tup = get_option_sec_id(venue, symbol, exp, strike);
|
||||
if (k_tup != null) {
|
||||
var id = cp == PutOrCall.Call ? k_tup.Item1 : k_tup.Item2;
|
||||
if (id.HasValue) {
|
||||
var id_val = id.Value;
|
||||
SecurityMD sec_md;
|
||||
if (sec_md_map.TryGetValue(id_val, out sec_md)) {
|
||||
return sec_md.security;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Tuple<uint?, uint?> get_option_sec_id(
|
||||
Venue venue, string symbol, DateTime exp, double strike) {
|
||||
var s_exp = new SecurityExpiration(venue, SecurityType.Option, symbol, exp);
|
||||
@@ -173,7 +190,7 @@ namespace mbts.spark {
|
||||
}
|
||||
IDictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> rv_data =
|
||||
new Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>>();
|
||||
return Tuple.Create(exp.to_security_expiration(), rv_data);
|
||||
return Tuple.Create(exp.to_security_expiration(type: SecurityType.Option), rv_data);
|
||||
}
|
||||
|
||||
internal IDictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> get_option_bbo(
|
||||
@@ -182,12 +199,11 @@ namespace mbts.spark {
|
||||
Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> rv =
|
||||
new Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>>();
|
||||
foreach (SecurityStrike k in strikes) {
|
||||
var (call_id, put_id) = k.call_put_id;
|
||||
// call
|
||||
uint? call_id = k.call_put_id.Item1;
|
||||
var call_sec_md = get_sec_md(call_id);
|
||||
VolSurfaceMDUnit call_bbo = call_sec_md == null ? VolSurfaceMDUnit.empty : call_sec_md.Item2;
|
||||
// put
|
||||
uint? put_id = k.call_put_id.Item2;
|
||||
var put_sec_md = get_sec_md(put_id);
|
||||
VolSurfaceMDUnit put_bbo = put_sec_md == null ? VolSurfaceMDUnit.empty : put_sec_md.Item2;
|
||||
rv.Add(k.strike, new Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>(call_bbo, put_bbo));
|
||||
@@ -243,5 +259,28 @@ namespace mbts.spark {
|
||||
kv.Value.Count > 0).Select(kv => kv.Key.expiration);
|
||||
}
|
||||
|
||||
public IEnumerable<SecurityMD> spreads {
|
||||
get {
|
||||
return sec_md_map.Where(kv => kv.Value.security.HasSpread)
|
||||
.Select(kv => kv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<SecurityMD> get_securities(Func<SecurityMD, bool> criteria) {
|
||||
return sec_md_map.Values.Where(sec_md => criteria(sec_md));
|
||||
}
|
||||
|
||||
public IEnumerable<SecurityMD> get_options(
|
||||
Venue? exchange, string option_name, DateTime? exp, double? strike, PutOrCall? cp) {
|
||||
return get_securities(sc => {
|
||||
var s = sc.security;
|
||||
return s.security_type() == SecurityType.Option &&
|
||||
(exchange == null || s.Exchange == exchange) &&
|
||||
(exp == null || s.earliest_expiration() == exp) &&
|
||||
(strike == null || s.strike() == strike) &&
|
||||
(cp == null || s.Option.CallPut == cp);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ namespace mbts.spark {
|
||||
/// from the same secondary thread.
|
||||
/// </summary>
|
||||
public class ThreadedBlackboard {
|
||||
private readonly string _bb_name;
|
||||
private IBus _bus;
|
||||
private List<IDisposable> _subs = new List<IDisposable>();
|
||||
private HashSet<object> _tag_map = new HashSet<object>();
|
||||
@@ -31,9 +32,10 @@ namespace mbts.spark {
|
||||
private IDictionary<object, object> _cache = new
|
||||
Dictionary<object, object>();
|
||||
private static int _tid() { return VolSurfaceTroubleshootingFunctions.tid(); }
|
||||
public ThreadedBlackboard(IBus bus) {
|
||||
bts.Log.Ui.info($"ThreadedBlackBoard.cons tid:{ _tid()}");
|
||||
public ThreadedBlackboard(string name, IBus bus) {
|
||||
bts.Log.Ui.info($"ThreadedBlackBoard.cons tid:{_tid()} bb_name: {name}");
|
||||
_bus = bus;
|
||||
_bb_name = name;
|
||||
subscribe(SparkTags.SparkTimer);
|
||||
System.Threading.Thread timer_thread = new System.Threading.Thread(() => {
|
||||
DateTime start_time = DateTime.Now;
|
||||
@@ -61,15 +63,13 @@ namespace mbts.spark {
|
||||
return;
|
||||
}
|
||||
_tag_map.Add(tag);
|
||||
bts.Log.Ui.info($"ThreadedBlackBoard.subscribe tag:{tag} tid:{ _tid()}");
|
||||
bts.Log.Ui.info($"ThreadedBlackBoard.subscribe tag:{tag} tid:{_tid()}");
|
||||
var observable = _bus.subscribe(tag).OnDispatcher().Subscribe(
|
||||
data => _on_bus_data(tag, data));
|
||||
_subs.Add(observable);
|
||||
}
|
||||
|
||||
public void post<T>(ITag<T> tag, T data, bool block_until_written = false) {
|
||||
bts.Log.Ui.diag($"ThreadedBlackBoard.post tag:{tag} data:{_data_string(data)} " +
|
||||
$"tid:{_tid()}");
|
||||
_cache[tag] = data;
|
||||
_bus.post(tag, data);
|
||||
}
|
||||
@@ -92,8 +92,6 @@ namespace mbts.spark {
|
||||
timer_callback();
|
||||
return;
|
||||
}
|
||||
bts.Log.Ui.diag($"ThreadedBlackBoard._on_bus_data tag:{tag} data:{_data_string(data)} " +
|
||||
$"tid:{_tid()}");
|
||||
data_callback(tag, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
using bts.api;
|
||||
using bts.api.analytics;
|
||||
using bts.collections;
|
||||
using bts.utils;
|
||||
|
||||
using IronPython.Compiler.Ast;
|
||||
|
||||
using mbts;
|
||||
using mbts.analytics;
|
||||
using mbts.spark;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.converters;
|
||||
using mbts.ui.shell;
|
||||
|
||||
using Spark.Core;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using mbts;
|
||||
using mbts.analytics;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.shell;
|
||||
using mbts.spark;
|
||||
using bts.utils;
|
||||
using bts.api;
|
||||
using bts.collections;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace mbts.spark {
|
||||
/// This contains the list of global values for the vol
|
||||
@@ -55,6 +63,27 @@ namespace mbts.spark {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static string log_string(this VolSurfaceCalculationRequest vs_req) {
|
||||
if (vs_req == null) {
|
||||
return "Null";
|
||||
}
|
||||
string action_str = String.Empty;
|
||||
foreach (var kv in vs_req.action_map) {
|
||||
action_str += $"exp: {kv.Key.ToString()} action: {kv.Value.ToString()}, ";
|
||||
}
|
||||
action_str = action_str.TrimEnd(',', ' ');
|
||||
return $"vs_inp: {vs_req.volsurface_input.log_string()}\nreq_id: {vs_req.request_id}\n" +
|
||||
$"action_map: {action_str}\nup: {vs_req.cascade_up} down: {vs_req.cascade_down}";
|
||||
}
|
||||
|
||||
public static string log_string(this VolSurfaceCalculationResponse resp) {
|
||||
if (resp == null) {
|
||||
return "Null";
|
||||
}
|
||||
return $"req_id: {resp.request_id} vs_output: " +
|
||||
$"{resp.volsurface_calculation_output.volsurface_input.log_string()}";
|
||||
}
|
||||
|
||||
private static string _trim_leading_char(string s, char c) {
|
||||
if (!s.is_null_or_empty() && s.EndsWith(c)) {
|
||||
return s.Remove(s.Length - 1, 1);
|
||||
@@ -63,11 +92,12 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
internal static string log_string(this VolSurfaceDisplayModel.DisplayModelData dm_data) {
|
||||
string rv = String.Empty;
|
||||
string global_grid_str = dm_data.global_grid == null ? "Null" : dm_data.global_grid.log_string();
|
||||
rv += $"global_grid: {global_grid_str} \n";
|
||||
string exp_grid_str = dm_data.exp_grid == null ? "Null" : dm_data.exp_grid.log_string();
|
||||
rv += $"exp_grid: {exp_grid_str} \n";
|
||||
var vs_output = dm_data.vs_output;
|
||||
var exp_grid = dm_data.exp_grid;
|
||||
var vs_output_str = vs_output == null ? "NULL" : vs_output.volsurface_input.log_string();
|
||||
var exp_grid_str = exp_grid == null ? "NULL" : exp_grid.log_string();
|
||||
var rv = $"DisplayModelData\nvs_output:\n{vs_output_str}\n" +
|
||||
$"exp_grid\n{exp_grid_str}\n";
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -83,19 +113,19 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
internal static string log_string(this VolSurfaceDisplayGrid dgrid) {
|
||||
Func<IDictionary<string, object>, string> log_exp = (map) => {
|
||||
Func<IDictionary<string, object>, string> log_exp = (col_val_map) => {
|
||||
string rv = String.Empty;
|
||||
foreach (var kv in map) {
|
||||
foreach (var kv in col_val_map) {
|
||||
string val_string = kv.Value == null ? "Null" : kv.Value.ToString();
|
||||
rv += $"{kv.Key}:{val_string},";
|
||||
rv += $"{kv.Key}: {val_string}, ";
|
||||
}
|
||||
return _trim_leading_char(rv, ',');
|
||||
};
|
||||
string rv = String.Empty;
|
||||
foreach (var kv in dgrid.data_map) {
|
||||
rv += $"Exp:{kv.Key.expiration.ToShortDateString()} Data:{log_exp(kv.Value)},";
|
||||
rv += $"Exp: {kv.Key.expiration.ToShortDateString()} Data: {log_exp(kv.Value)}\n";
|
||||
}
|
||||
return _trim_leading_char(rv, ',');
|
||||
return rv;
|
||||
}
|
||||
|
||||
internal static string log_string(this OptionDriverPriceMap map) {
|
||||
@@ -132,7 +162,7 @@ namespace mbts.spark {
|
||||
|
||||
internal static string log_string(this Theos t) {
|
||||
string rv = $"strike: {t.strike} fwd: {t.fwd} driver: {t.driver} " +
|
||||
$"move: { t.move} vol: {t.vol} c_theo: {t.call} " +
|
||||
$"move: {t.move} vol: {t.vol} c_theo: {t.call} " +
|
||||
$"p_theo: {t.put}";
|
||||
return rv;
|
||||
}
|
||||
@@ -151,8 +181,8 @@ namespace mbts.spark {
|
||||
foreach (var kv in sc_data.strike_map) {
|
||||
var exp = kv.Key;
|
||||
foreach (var k in kv.Value) {
|
||||
rv += $"exp: {exp} k: {k} c_id: {k_id(k.call_put_id.Item1)} " +
|
||||
$"p_id: {k.call_put_id.Item2}" + "\n";
|
||||
rv += $"exp: {exp} k: {k} c_id: {k_id(k.call_put_id.call)} " +
|
||||
$"p_id: {k.call_put_id.put}" + "\n";
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
@@ -178,6 +208,67 @@ namespace mbts.spark {
|
||||
return rv;
|
||||
}
|
||||
|
||||
internal static string log_string(this ComboFullData cf_data) {
|
||||
string rv = String.Empty;
|
||||
if (cf_data.option_expirations != null) {
|
||||
foreach (var kv in cf_data.option_pos_map) {
|
||||
var exp = kv.Key;
|
||||
foreach (var kv_in in kv.Value) {
|
||||
double k = kv_in.Key;
|
||||
ComboStrikeData kp = kv_in.Value;
|
||||
rv += $"exp: {exp.ToString()} k: {k} Pos: {kp.call_pos},{kp.put_pos} ({kp.call_raw_pos},{kp.put_raw_pos}) ";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cf_data.future_pos_map != null) {
|
||||
foreach (var kv in cf_data.future_pos_map) {
|
||||
rv += $"exp: {kv.Key.ToString()} {kv.Value.Item1},{kv.Value.Item2} ";
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
internal static string log_string(this SlideFullData sl_data) {
|
||||
Func<SlideGreekUnitKey, string> sguk_str = (sguk) => sguk.display_name;
|
||||
Func<SlideGreekUnit, string> sgu_str = (sgu) => {
|
||||
if (sgu == null)
|
||||
return "No Handles";
|
||||
string rv = $"Handle: {sgu.driver_price} ";
|
||||
foreach (double d in sgu.position_greeks)
|
||||
rv += $"{d}, ";
|
||||
rv = rv.Trim();
|
||||
if (rv.EndsWith(","))
|
||||
rv = rv.TrimEnd(',');
|
||||
return rv;
|
||||
};
|
||||
string rv = String.Empty;
|
||||
foreach (var kv in sl_data.map) {
|
||||
rv += $"SlideGreekUnitKey: {sguk_str(kv.Key)}\n";
|
||||
foreach (var i_kv in kv.Value) {
|
||||
rv += sgu_str(i_kv.Value) + "\n";
|
||||
}
|
||||
}
|
||||
rv += $"Overriden?: {sl_data.ui_override != null}";
|
||||
return rv;
|
||||
}
|
||||
|
||||
internal static string log_string(this VolSurfaceUsageListImmutable vsu_list) {
|
||||
string rv = "VolSurfaceUsageList:";
|
||||
foreach (var u in vsu_list.UsageList) {
|
||||
rv += $" {u.SecTup.Symbol}:{u.VsId}";
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
internal static string log_string(this IPNLUnit p) {
|
||||
string rv = "IPNLUnit:";
|
||||
rv += $" account: {p.account} sec: {p.security.security_desc()} driver: {p.driver} theo: {p.theo} settle: {p.settle_price}" +
|
||||
$" start_pos: {p.start_long_pos - p.start_short_pos} day_pos: {p.day_long_pos - p.day_short_pos}" +
|
||||
$" start_pnl: {p.start_pnl} start_delta: {p.start_delta} start_vega: {p.start_vega}" +
|
||||
$" day_pnl: {p.day_pnl} day_delta: {p.day_delta} day_vega: {p.day_vega}";
|
||||
return rv;
|
||||
}
|
||||
|
||||
internal static int tid() {
|
||||
return System.Threading.Thread.CurrentThread.ManagedThreadId;
|
||||
}
|
||||
|
||||
@@ -86,9 +86,14 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
private void _save_exp_params() {
|
||||
var exp_params = new AnalyticsExpirationParameters[]{
|
||||
new AnalyticsExpirationParameters(option_exp1, driver_exp, driver_exp, driver_exp, 0, 0, Double.NaN, 1, 1),
|
||||
new AnalyticsExpirationParameters(option_exp2, driver_exp, driver_exp, driver_exp, 0, 0, Double.NaN, 1, 1),
|
||||
var api_driver = new ExpirationDriverImmutable(new() {
|
||||
Security = driver_exp.to_api_sec_exp()
|
||||
});
|
||||
var exp_params = new AnalyticsExpirationParameters[] {
|
||||
new AnalyticsExpirationParameters(
|
||||
option_exp1, api_driver, driver_exp, driver_exp, 0, 0, double.NaN, 1, 1),
|
||||
new AnalyticsExpirationParameters(
|
||||
option_exp2, api_driver, driver_exp, driver_exp, 0, 0, double.NaN, 1, 1),
|
||||
};
|
||||
_bb.post(SparkTags.ExpirationParametersCommitTag, exp_params);
|
||||
}
|
||||
@@ -103,4 +108,4 @@ namespace mbts.spark {
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,24 @@ namespace mbts.ui.controls {
|
||||
VolSurfaceExpiration exp = p.Key;
|
||||
VolCurveOutput exp_output = p.Value;
|
||||
IDictionary<VolSurfaceDisplayGridColumn, object> out_exp_map = VolSurfaceUIAdapterUtils.get_exp_data(ref out_grid, exp);
|
||||
out_exp_map[_fwd_col] = exp_output == null ? Double.NaN : exp_output.fwd;
|
||||
out_exp_map[_ref_fwd_col] = exp_output != null && exp_output.adjusted_curve_parameters != null && exp_output.adjusted_curve_parameters.core_parameters != null ?
|
||||
exp_output.adjusted_curve_parameters.core_parameters.ref_forward : Double.NaN;
|
||||
out_exp_map[_live_driver_col] = (exp_output != null && exp_output.aux_data != null) ? exp_output.aux_data.driver_price : Double.NaN;
|
||||
out_exp_map[_driver_override_col] = exp_output.adjusted_curve_parameters.core_parameters.driver_override;
|
||||
out_exp_map[_fwd_col] = exp_output?.fwd ?? double.NaN;
|
||||
|
||||
out_exp_map[_ref_fwd_col] = exp_output
|
||||
?.adjusted_curve_parameters
|
||||
?.core_parameters
|
||||
?.ref_forward
|
||||
?? double.NaN;
|
||||
|
||||
out_exp_map[_live_driver_col] = exp_output
|
||||
?.aux_data
|
||||
?.driver_price
|
||||
?? double.NaN;
|
||||
|
||||
out_exp_map[_driver_override_col] = exp_output
|
||||
?.adjusted_curve_parameters
|
||||
?.core_parameters
|
||||
?.driver_override
|
||||
?? double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,15 +3,16 @@ namespace mbts.spark {
|
||||
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls.graph;
|
||||
using mbts.ui.shell;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[ProtoContract]
|
||||
class VolSurfaceGraphSettings : IEquatable<VolSurfaceGraphSettings>, ICloneable {
|
||||
class VolSurfaceGraphSettings : IProtobuf<VolSurfaceGraphSettings> {
|
||||
public static VolSurfaceGraphSettings get_default() {
|
||||
return new VolSurfaceGraphSettings {
|
||||
put_control_points = new ScatterSeriesSettings {
|
||||
@@ -109,8 +110,8 @@ namespace mbts.spark {
|
||||
// }
|
||||
//}
|
||||
|
||||
public object Clone() =>
|
||||
ProtoBufSerializationHelper.clone_protobuf(this);
|
||||
public VolSurfaceGraphSettings Clone() =>
|
||||
ProtobufSerializationHelper.clone(this);
|
||||
|
||||
public bool Equals(VolSurfaceGraphSettings other) =>
|
||||
other != null &&
|
||||
|
||||
@@ -6,6 +6,10 @@ using mbts.analytics;
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.utility;
|
||||
|
||||
using Spark.Core;
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@@ -51,7 +55,7 @@ namespace mbts.spark {
|
||||
var vs_removes = removed.Select(exp => exp.ToVSExp());
|
||||
|
||||
var true_removed = removed.Where(rmv => !vs_adds.Contains(rmv.ToVSExp()));
|
||||
var true_added = added.Where(add => !vs_removes.Contains(add.ToVSExp()));
|
||||
var true_added = added.Except(vs_removes.Concat(_hidden_exps), v => v.ToVSExp());
|
||||
var changed_calc_modes = added.Where(add => vs_removes.Contains(add.ToVSExp()));
|
||||
|
||||
foreach (var tr in true_removed) {
|
||||
@@ -61,16 +65,10 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var ta in true_added) {
|
||||
if (_hidden_exps.Contains(ta.ToVSExp()) ||
|
||||
!rows.TryGetFirst(r => r.expiration.expiration == ta.expiration, out var row)) {
|
||||
continue;
|
||||
}
|
||||
visible_rows.InsertSorted(row,
|
||||
Comparer<IExpirationBasedRow>.Create(
|
||||
(r1, r2) => r1.expiration.CompareTo(r2.expiration))
|
||||
.wrap<IExpirationBasedRow, object>());
|
||||
}
|
||||
var comp = ComparerWrapper<object>.wrap_cast(
|
||||
NullCheckComparer.create<IExpirationBasedRow>(
|
||||
(r1, r2) => r1.expiration.CompareTo(r2.expiration)));
|
||||
visible_rows.InsertSorted(true_added, comp);
|
||||
|
||||
foreach (var ccm in changed_calc_modes) {
|
||||
int index = visible_rows
|
||||
|
||||
@@ -10,6 +10,10 @@ namespace mbts.spark {
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.utility;
|
||||
|
||||
using Spark.Analytics.View;
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
@@ -27,13 +31,13 @@ namespace mbts.spark {
|
||||
readonly LinearAxisVM _x_axis = new() { position = AxisPosition.BottomLeftToRight };
|
||||
readonly LinearAxisVM _y_axis = new() { position = AxisPosition.LeftBottomToTop };
|
||||
readonly Dictionary<SecurityExpiration, ExpGraphBounds> _expiration_graph_bounds;
|
||||
readonly VolSurfaceGraphSettings _settings;
|
||||
readonly ObservableCollection<VolSurfaceDisplayGridExpiration> _expirations = new();
|
||||
readonly Dictionary<VolSurfaceDisplayGridExpiration, SeriesSetVM> _expiration_series_cache = new();
|
||||
|
||||
VolSurfaceExpiration _md_exp;
|
||||
VolSurfaceDisplayGridExpiration _expiration;
|
||||
VolSurfaceDisplayGridExpiration _earliest_selected_expiration;
|
||||
VolSurfaceGraphSettings _settings;
|
||||
object _implied_vol_market_side = ImpliedVolHelper.None;
|
||||
bool _show_vol_path;
|
||||
|
||||
@@ -46,7 +50,9 @@ namespace mbts.spark {
|
||||
if (startup_data.vol_curve_x_axis == null) {
|
||||
var x_axis = BTSOxyGraphAxisDouble.Default;
|
||||
x_axis.name = "Strike";
|
||||
x_axis.axis_line_color = BTSColors.Graph.axis_line;
|
||||
x_axis.major_grid_line_color = BTSColors.Graph.grid_line;
|
||||
x_axis.tick_line_color = BTSColors.Graph.tick_line;
|
||||
x_axis.position = AxisPosition.BottomLeftToRight;
|
||||
x_axis.minimum = 0;
|
||||
x_axis.maximum = 2000;
|
||||
@@ -58,7 +64,9 @@ namespace mbts.spark {
|
||||
if (startup_data.vol_curve_y_axis == null) {
|
||||
var y_axis = BTSOxyGraphAxisDouble.Default;
|
||||
y_axis.name = "Volatility";
|
||||
y_axis.axis_line_color = BTSColors.Graph.axis_line;
|
||||
y_axis.major_grid_line_color = BTSColors.Graph.grid_line;
|
||||
y_axis.tick_line_color = BTSColors.Graph.tick_line;
|
||||
y_axis.position = AxisPosition.LeftBottomToTop;
|
||||
y_axis.minimum = 0;
|
||||
y_axis.maximum = 1;
|
||||
@@ -78,13 +86,17 @@ namespace mbts.spark {
|
||||
if (_model.get_active_settings() is not VolSurfaceSettings vss) {
|
||||
return null;
|
||||
}
|
||||
// return new VolSurfaceGraphSettingsEditor {
|
||||
// DataContext = new VolSurfaceGraphSettingsEditorVM(vss.core_settings.vol_surface_name, ProtoBufSerializationHelper.clone_protobuf(_settings), settings => {
|
||||
// _settings = settings;
|
||||
// _recreate_series();
|
||||
// })
|
||||
// };
|
||||
return null;
|
||||
var vm = new VolSurfaceGraphSettingsVM(vss.core_settings.vol_surface_name);
|
||||
vm.load_from(_settings.Clone());
|
||||
vm.request_commit += commit;
|
||||
return new VolSurfaceGraphSettingsWindow {
|
||||
DataContext = vm
|
||||
};
|
||||
|
||||
void commit(VolSurfaceGraphSettings settings) {
|
||||
_settings = settings;
|
||||
_recreate_series();
|
||||
}
|
||||
});
|
||||
graph_vm = new BTSGraphVM {
|
||||
plot_area_background = Colors.Transparent,
|
||||
@@ -113,7 +125,7 @@ namespace mbts.spark {
|
||||
})
|
||||
.BufferLatest(TimeSpan.FromSeconds(0.1))
|
||||
.OnDispatcher()
|
||||
.SelectManyInSeries(series => Observable.Create<SeriesVM>(o => {
|
||||
.SelectSeries(series => Observable.Create<SeriesVM>(o => {
|
||||
o.OnNext(null);
|
||||
return Disposable.Create(series
|
||||
.Select(svm => svm.points.Subscribe((s, e) => o.OnNext(svm)))
|
||||
@@ -181,6 +193,20 @@ namespace mbts.spark {
|
||||
static (double call_wing_start, double put_wing_start) _get_actual_wing_starts(VolCurveDisplayGraph disp_graph) =>
|
||||
disp_graph.all_points.Select(p => p.Item1).MinMax() ?? (double.NaN, double.NaN);
|
||||
|
||||
void _recreate_series() {
|
||||
/// 'graph_vm.series_set' is bound to '_expirations', so clearing and re-adding expirations
|
||||
/// in turn regenerates the series. '_expiration_series_cache' must
|
||||
/// be cleared as well, otherwise cached series vms would just be back to the collection
|
||||
/// ('graph_vm.series_set').
|
||||
var visible_exp = _earliest_selected_expiration;
|
||||
_expiration_series_cache.Clear();
|
||||
_expirations.SetItems(_model.get_ordered_expirations());
|
||||
foreach (var svm in graph_vm.series.OfType<SeriesSetVM>()) {
|
||||
svm.is_visible = svm.args.Equals(visible_exp);
|
||||
}
|
||||
_update();
|
||||
}
|
||||
|
||||
void _expirations_changed(IEnumerable<VolSurfaceDisplayGridExpiration> added, IEnumerable<VolSurfaceDisplayGridExpiration> removed) {
|
||||
_expirations.sync_with(_model.get_ordered_expirations());
|
||||
_update();
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
namespace mbts.spark {
|
||||
using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
class VolGridCellVM : DisposableViewModelBase {
|
||||
readonly Property<object> _candidate_value;
|
||||
readonly Property<object> _committed_value;
|
||||
readonly Property<bool> _is_dirty;
|
||||
|
||||
public VolGridCellVM(string column_id) {
|
||||
this.column_id = column_id ?? throw new ArgumentNullException(nameof(column_id));
|
||||
_committed_value = backing<object>(nameof(committed_value));
|
||||
_candidate_value = backing<object>(nameof(candidate_value));
|
||||
_is_dirty = backing(nameof(is_dirty),
|
||||
_committed_value.observe_current(true)
|
||||
.CombineLatest(_candidate_value.observe_current(true))
|
||||
.Select(tup => !Equals(tup.First, tup.Second))
|
||||
.OnDispatcher());
|
||||
}
|
||||
|
||||
public string column_id { get; }
|
||||
|
||||
public object committed_value {
|
||||
get => _committed_value.Value;
|
||||
set => _committed_value.set(value);
|
||||
}
|
||||
|
||||
public object candidate_value {
|
||||
get => _candidate_value.Value;
|
||||
set => _candidate_value.set(value);
|
||||
}
|
||||
|
||||
public bool is_dirty => _is_dirty.Value;
|
||||
|
||||
public IObservable<object> observe_candidate(bool start_immediately = false) =>
|
||||
_candidate_value.observe_current(start_immediately);
|
||||
|
||||
public void revert() =>
|
||||
candidate_value = committed_value;
|
||||
|
||||
public override string ToString() =>
|
||||
$"column_id: {column_id}, committed: {committed_value}, candidate: {candidate_value}";
|
||||
}
|
||||
|
||||
class VolGridCellVM<T> : VolGridCellVM {
|
||||
public VolGridCellVM(string column_id) : base(column_id) { }
|
||||
|
||||
public VolGridCellVM(string column_id, T committed_value, T candidate_value) : base(column_id) {
|
||||
this.committed_value = committed_value;
|
||||
this.candidate_value = candidate_value;
|
||||
}
|
||||
|
||||
public new T committed_value {
|
||||
get => base.committed_value is T v ? v : default;
|
||||
set => base.committed_value = value;
|
||||
}
|
||||
|
||||
public new T candidate_value {
|
||||
get => base.candidate_value is T v ? v : default;
|
||||
set => base.candidate_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
class VolGridTickCellVM : VolGridCellVM {
|
||||
ICommand _tick_up_cmd;
|
||||
ICommand _tick_down_cmd;
|
||||
|
||||
public VolGridTickCellVM(string column_id) : base(column_id) { }
|
||||
|
||||
public event Action<bool> request_tick;
|
||||
|
||||
public ICommand tick_up_cmd =>
|
||||
_tick_up_cmd ??= new DelegateCommand(() =>
|
||||
request_tick?.Invoke(true));
|
||||
|
||||
public ICommand tick_down_cmd =>
|
||||
_tick_down_cmd ??= new DelegateCommand(() =>
|
||||
request_tick?.Invoke(false));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark.VolSurface {
|
||||
using System.Windows.Media;
|
||||
|
||||
readonly struct VolSurfaceCellState {
|
||||
public bool is_dirty => committed_text is not null;
|
||||
|
||||
public FormattedText? text { get; init; }
|
||||
public FormattedText? committed_text { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.shell;
|
||||
|
||||
using Spark.Core;
|
||||
|
||||
using System;
|
||||
|
||||
class VolSurfaceCellVM : DisposableViewModelBase {
|
||||
readonly Property<object?> _candidate_value;
|
||||
readonly Property<object?> _committed_value;
|
||||
readonly DelegateProperty<bool> _is_dirty;
|
||||
readonly DeferrableAction _refresh;
|
||||
|
||||
public VolSurfaceCellVM(
|
||||
VolSurfaceDisplayGridExpiration expiration, VolSurfaceDisplayGridColumn column) {
|
||||
this.column = column ?? throw new ArgumentNullException(nameof(column));
|
||||
this.expiration = expiration ?? throw new ArgumentNullException(nameof(expiration));
|
||||
_committed_value = backing<object?>(nameof(committed_value), column.comparer);
|
||||
_candidate_value = backing<object?>(nameof(candidate_value), column.comparer);
|
||||
_is_dirty = backing(
|
||||
nameof(is_dirty), () => !column.comparer.Equals(candidate_value, committed_value));
|
||||
_refresh = new(_is_dirty.refresh);
|
||||
_committed_value.Changed += on_committed_changed;
|
||||
_candidate_value.Changed += on_candidate_changed;
|
||||
_is_dirty.Changed += (o, n) => {
|
||||
Log.assert(o != n);
|
||||
Log.Ui.info(
|
||||
$"VolSurface '{expiration}.{column}' is_dirty changed to {n}. " +
|
||||
$"commited: {committed_value}; candidate: {candidate_value}");
|
||||
};
|
||||
|
||||
void on_committed_changed(object? oldval, object? newval) =>
|
||||
_is_dirty.refresh();
|
||||
|
||||
void on_candidate_changed(object? oldval, object? newval) =>
|
||||
_is_dirty.refresh();
|
||||
}
|
||||
|
||||
public event PropertyChange<object?>? candidate_value_changed {
|
||||
add => _candidate_value.Changed += value;
|
||||
remove => _candidate_value.Changed -= value;
|
||||
}
|
||||
|
||||
public VolSurfaceDisplayGridColumn column { get; }
|
||||
public string column_id => column.unique_col_name;
|
||||
public VolSurfaceDisplayGridExpiration expiration { get; }
|
||||
|
||||
public object? committed_value {
|
||||
get => _committed_value.Value;
|
||||
set => _committed_value.set(value);
|
||||
}
|
||||
|
||||
public object? candidate_value {
|
||||
get => _candidate_value.Value;
|
||||
set => _candidate_value.set(value);
|
||||
}
|
||||
|
||||
public bool is_dirty => _is_dirty.Value;
|
||||
|
||||
public IObservable<object?> observe_candidate(bool start_immediately = false) =>
|
||||
_candidate_value.observe_current(start_immediately);
|
||||
|
||||
public void reset(object? committed_value, object? candidate_value) {
|
||||
using var _ = _refresh.defer();
|
||||
this.committed_value = committed_value;
|
||||
this.candidate_value = candidate_value;
|
||||
}
|
||||
|
||||
public void revert() =>
|
||||
candidate_value = committed_value;
|
||||
|
||||
public override string ToString() =>
|
||||
$"column: {column}, committed: {committed_value}, candidate: {candidate_value}";
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ namespace mbts.spark.VolSurface {
|
||||
id = key ?? throw new InvalidOperationException("Column key cannot be null");
|
||||
}
|
||||
|
||||
public VolSurfaceDisplayGridColumn model { get; set; }
|
||||
public VolSurfaceDisplayGridColumn model { get; }
|
||||
public VolSurfaceColumnType type => model.type;
|
||||
|
||||
public new VolSurfaceColumnSettings create() {
|
||||
@@ -43,7 +43,7 @@ namespace mbts.spark.VolSurface {
|
||||
static Thickness _header_cell_padding => new(6, 0, 4, 0);
|
||||
|
||||
IValueConverter _data_context_converter =>
|
||||
ValueConverter.create<VolSurfaceRowContext, object>(row => row?.get_cell(model));
|
||||
ValueConverter.create<VolSurfaceRowVM, object>(row => row?.get_cell(model));
|
||||
|
||||
public override FrameworkElement view_factory() {
|
||||
return type switch {
|
||||
@@ -58,7 +58,7 @@ namespace mbts.spark.VolSurface {
|
||||
HorizontalAlignment = HorizontalAlignment.Left,
|
||||
Foreground = BTSColors.header_text.to_brush(),
|
||||
};
|
||||
text.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceRowContext.expiration)));
|
||||
text.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceRowVM.expiration)));
|
||||
var bd = new Border {
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
Padding = _header_cell_padding,
|
||||
@@ -73,12 +73,12 @@ namespace mbts.spark.VolSurface {
|
||||
var view = new TextBlock {
|
||||
HorizontalAlignment = HorizontalAlignment.Right,
|
||||
Margin = _cell_padding,
|
||||
Foreground = Brushes.Blue,
|
||||
Foreground = BTSColors.VolSurfaceGrid.readonly_column_foreground
|
||||
};
|
||||
view.SetBinding(FrameworkElement.DataContextProperty, new Binding() {
|
||||
Converter = _data_context_converter
|
||||
});
|
||||
view.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolGridCellVM.candidate_value)) {
|
||||
view.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceCellVM.candidate_value)) {
|
||||
Converter = ValueConverter.create(obj => model.format(obj))
|
||||
});
|
||||
return view;
|
||||
@@ -101,16 +101,16 @@ namespace mbts.spark.VolSurface {
|
||||
view.SetBinding(FrameworkElement.DataContextProperty, new Binding() {
|
||||
Converter = _data_context_converter
|
||||
});
|
||||
view.SetBinding(VolSurfaceCellView.CommittedValueProperty, new Binding(nameof(VolGridCellVM.committed_value)) {
|
||||
view.SetBinding(VolSurfaceCellView.CommittedValueProperty, new Binding(nameof(VolSurfaceCellVM.committed_value)) {
|
||||
Mode = BindingMode.OneWay,
|
||||
Converter = ValueConverter.create(obj => model.format(obj))
|
||||
});
|
||||
view.SetBinding(VolSurfaceCellView.CandidateValueProperty, new Binding(nameof(VolGridCellVM.candidate_value)) {
|
||||
view.SetBinding(VolSurfaceCellView.CandidateValueProperty, new Binding(nameof(VolSurfaceCellVM.candidate_value)) {
|
||||
Mode = BindingMode.TwoWay,
|
||||
Converter = ValueConverter.create<object, string>(obj => model.format(obj), obj => model.parse(obj))
|
||||
});
|
||||
view.SetBinding(VolSurfaceCellView.TickDownCommandProperty, new Binding(nameof(VolGridTickCellVM.tick_down_cmd)));
|
||||
view.SetBinding(VolSurfaceCellView.TickUpCommandProperty, new Binding(nameof(VolGridTickCellVM.tick_up_cmd)));
|
||||
view.SetBinding(VolSurfaceCellView.TickDownCommandProperty, new Binding(nameof(VolSurfaceTickCellVM.tick_down_cmd)));
|
||||
view.SetBinding(VolSurfaceCellView.TickUpCommandProperty, new Binding(nameof(VolSurfaceTickCellVM.tick_up_cmd)));
|
||||
var bd = new Border {
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
namespace mbts.spark.VolSurface {
|
||||
#nullable enable
|
||||
namespace mbts.spark.VolSurface {
|
||||
using bts;
|
||||
using bts.collections;
|
||||
using bts.utils;
|
||||
@@ -11,6 +12,10 @@
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.utility;
|
||||
|
||||
using Spark.Core;
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@@ -25,17 +30,20 @@
|
||||
class VolSurfaceGridVM : DisposableViewModelBase {
|
||||
readonly VolSurfaceVM _parent;
|
||||
readonly ObservableCollection<VolSurfaceDisplayGridExpiration> _expirations = new();
|
||||
readonly DeferrableActionWrapper _invalidate_rows;
|
||||
readonly DeferrableAction _invalidate_rows;
|
||||
readonly ColumnsModel _columns_model;
|
||||
|
||||
ISet<string> _hidden_columns;
|
||||
ISet<VolSurfaceExpiration> _hidden_expirations;
|
||||
IDisposable _shift_editor;
|
||||
ISet<VolSurfaceExpiration>? _hidden_expirations;
|
||||
IDisposable? _shift_editor;
|
||||
|
||||
public VolSurfaceGridVM(VolSurfaceVM vm, VolSurfaceDisplayModel model,
|
||||
ISet<string> hidden_columns, ISet<VolSurfaceExpiration> hidden_expirations) {
|
||||
Log.assert(hidden_columns != null);
|
||||
Log.assert(hidden_expirations != null);
|
||||
public VolSurfaceGridVM(
|
||||
VolSurfaceVM vm,
|
||||
VolSurfaceDisplayModel model,
|
||||
ISet<string> hidden_columns,
|
||||
ISet<VolSurfaceExpiration> hidden_expirations) {
|
||||
Log.notnull(hidden_columns);
|
||||
Log.notnull(hidden_expirations);
|
||||
_parent = vm;
|
||||
this.model = model;
|
||||
_columns_model = new(create_exp_column_view());
|
||||
@@ -63,16 +71,31 @@
|
||||
};
|
||||
|
||||
_dispose = Disposable.Create(
|
||||
ObservableAutoWrapper.connect(_expirations, rows, exp => new VolSurfaceRowContext(this, exp), row => row.Dispose()),
|
||||
ObservableAutoWrapper.connect(_expirations, rows, row_factory),
|
||||
ObservableAutoWrapper.connect_item_hooks(rows, connect_row),
|
||||
sorted_visible_rows.bind(visible_rows),
|
||||
Disposable.Create(() => {
|
||||
this.model.on_candidate_grid_change -= _on_grid_updated;
|
||||
this.model.on_committed_grid_change -= _on_grid_updated;
|
||||
Disposable.dispose(rows);
|
||||
rows.DisposeAll(true);
|
||||
Disposable.dispose(ref _shift_editor);
|
||||
}),
|
||||
_columns_model);
|
||||
|
||||
VolSurfaceRowVM row_factory(VolSurfaceDisplayGridExpiration exp) =>
|
||||
new(this, exp);
|
||||
|
||||
IDisposable connect_row(VolSurfaceRowVM row) {
|
||||
row.request_calculate += request_recalc;
|
||||
return Disposable.Create(() => {
|
||||
row.request_calculate -= request_recalc;
|
||||
row.Dispose();
|
||||
});
|
||||
|
||||
void request_recalc() =>
|
||||
model.set_candidate_grid(current_grid);
|
||||
}
|
||||
|
||||
VolSurfaceColumn create_exp_column_view() {
|
||||
var filter = new ComboCheckBox();
|
||||
filter.SetResourceReference(FrameworkElement.StyleProperty, "ExpirationFilterDropDown");
|
||||
@@ -92,7 +115,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<IEnumerable<VolSurfaceDisplayGridExpiration>> on_selection_changed;
|
||||
public event Action<IEnumerable<VolSurfaceDisplayGridExpiration>>? on_selection_changed;
|
||||
|
||||
public VolSurfaceDisplayGrid current_grid { get; private set; }
|
||||
public VolSurfaceDisplayGrid committed_grid { get; private set; }
|
||||
@@ -102,14 +125,14 @@
|
||||
public IReadOnlyObservableCollection<DIYGrid.ColumnBase> columns =>
|
||||
_columns_model.views_with_header_ro;
|
||||
|
||||
public ObservableCollection<VolSurfaceRowContext> rows { get; } = new();
|
||||
public ObservableCollection<VolSurfaceRowContext> visible_rows { get; } = new();
|
||||
public ObservableSortedCollection<VolSurfaceRowContext> sorted_visible_rows { get; } = new(_row_comparer);
|
||||
public ObservableCollection<VolSurfaceRowVM> rows { get; } = new();
|
||||
public ObservableCollection<VolSurfaceRowVM> visible_rows { get; } = new();
|
||||
public ObservableSortedCollection<VolSurfaceRowVM> sorted_visible_rows { get; } = new(_row_comparer);
|
||||
|
||||
public bool any_masters_selected =>
|
||||
selected_rows.select_display_exp().where_master().Any();
|
||||
|
||||
public IEnumerable<VolSurfaceRowContext> selected_rows =>
|
||||
public IEnumerable<VolSurfaceRowVM> selected_rows =>
|
||||
visible_rows.where_selected();
|
||||
|
||||
public IEnumerable<DIYGridSuperHeaderVM> super_headers =>
|
||||
@@ -118,13 +141,14 @@
|
||||
.Select(group => new DIYGridSuperHeaderVM(group.Key, group.Count(), collapsed_content: _short_header(group.Key)))
|
||||
.ToList();
|
||||
|
||||
public ICommand main_settings_command => _parent.main_settings_command;
|
||||
public ICommand advanced_settings_command => _parent.advanced_settings_command;
|
||||
public ICommand graph_settings_command => _parent.vol_curve_vm.settings_command;
|
||||
public ICommand grid_settings_command => _parent.grid_settings_command;
|
||||
public ICommand populate_empty_exps_cmd => _parent.populate_empty_exps_cmd;
|
||||
public ICommand main_settings_cmd => _parent.main_settings_cmd;
|
||||
public ICommand advanced_settings_cmd => _parent.advanced_settings_cmd;
|
||||
public ICommand graph_settings_cmd => _parent.vol_curve_vm.settings_command;
|
||||
public ICommand grid_settings_cmd => _parent.grid_settings_cmd;
|
||||
|
||||
static IComparer<VolSurfaceRowContext> _row_comparer =>
|
||||
Comparer<VolSurfaceDisplayGridExpiration>.Default.wrap<VolSurfaceDisplayGridExpiration, VolSurfaceRowContext>(r => r.expiration);
|
||||
static IComparer<VolSurfaceRowVM> _row_comparer =>
|
||||
Comparer<VolSurfaceDisplayGridExpiration>.Default.wrap<VolSurfaceDisplayGridExpiration, VolSurfaceRowVM>(r => r.expiration);
|
||||
|
||||
public void load_from(VolSurfaceMacroGridSettings grid_settings) {
|
||||
_hidden_columns = new HashSet<string>(grid_settings.hidden_cols());
|
||||
@@ -141,13 +165,14 @@
|
||||
rows.select_exp().Except(visible_rows.select_exp());
|
||||
|
||||
public void invalidate_rows() =>
|
||||
_invalidate_rows.execute();
|
||||
_invalidate_rows.Invoke();
|
||||
|
||||
public IDisposable defer_invalidate_rows() =>
|
||||
_invalidate_rows.defer_execution();
|
||||
_invalidate_rows.defer();
|
||||
|
||||
public VolSurfaceColumn get_column(string id) =>
|
||||
columns.FirstOrDefault(c => c.id == id) as VolSurfaceColumn;
|
||||
columns.FirstOrDefault(c => c.id == id) as VolSurfaceColumn ??
|
||||
throw new InvalidOperationException($"Failed to find column '{id}'");
|
||||
|
||||
internal void signal_selection_changed() {
|
||||
var e = on_selection_changed;
|
||||
@@ -193,23 +218,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
internal void copy_to_selection(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
|
||||
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
|
||||
_replicate(exp, selected_rows.select_display_exp().Except(exp), _get_columns(column, set));
|
||||
}
|
||||
}
|
||||
internal void copy_to_selection(
|
||||
VolSurfaceDisplayGridExpiration exp,
|
||||
VolSurfaceDisplayGridColumn column,
|
||||
GridColumnSet set) =>
|
||||
_replicate(exp, selected_rows.select_display_exp().Except(exp), _get_columns(column, set));
|
||||
|
||||
internal void copy_to_masters(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
|
||||
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
|
||||
_replicate(exp, _expirations.where_master().Except(exp), _get_columns(column, set));
|
||||
}
|
||||
}
|
||||
internal void copy_to_masters(
|
||||
VolSurfaceDisplayGridExpiration exp,
|
||||
VolSurfaceDisplayGridColumn column,
|
||||
GridColumnSet set) =>
|
||||
_replicate(exp, _expirations.where_master().Except(exp), _get_columns(column, set));
|
||||
|
||||
internal void copy_to_all(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
|
||||
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
|
||||
_replicate(exp, _expirations.Except(exp), _get_columns(column, set));
|
||||
}
|
||||
}
|
||||
internal void copy_to_all(
|
||||
VolSurfaceDisplayGridExpiration exp,
|
||||
VolSurfaceDisplayGridColumn column,
|
||||
GridColumnSet set) =>
|
||||
_replicate(exp, _expirations.Except(exp), _get_columns(column, set));
|
||||
|
||||
static string _short_header(string header) =>
|
||||
string.Join("", header.Where(Char.IsUpper));
|
||||
@@ -218,7 +243,7 @@
|
||||
!_hidden_columns.Contains(column.unique_col_name);
|
||||
|
||||
void _on_grid_updated() {
|
||||
using var _ = _invalidate_rows.defer_execution();
|
||||
using var _ = _invalidate_rows.defer();
|
||||
var grid_new = model.get_active_grid();
|
||||
// add/remove columns
|
||||
var cols_new = grid_new.get_ordered_columns()
|
||||
@@ -243,7 +268,7 @@
|
||||
}
|
||||
current_grid = grid_new;
|
||||
committed_grid = is_dirty ? model.get_committed_grid() : current_grid;
|
||||
_invalidate_rows.execute();
|
||||
_invalidate_rows.Invoke();
|
||||
}
|
||||
|
||||
void _launch_shift_editor(VolSurfaceDisplayGridColumn column, Action<double> commit_shift) {
|
||||
@@ -299,7 +324,7 @@
|
||||
VolSurfaceDisplayGridExpiration source,
|
||||
IEnumerable<VolSurfaceDisplayGridExpiration> target_exps,
|
||||
IEnumerable<VolSurfaceDisplayGridColumn> cols) {
|
||||
foreach (var col in cols) {
|
||||
foreach (var col in cols.Where(c => c.type.is_editable())) {
|
||||
foreach (var exp in target_exps) {
|
||||
_copy(source, exp, col);
|
||||
}
|
||||
@@ -307,7 +332,14 @@
|
||||
_commit();
|
||||
}
|
||||
|
||||
void _copy(VolSurfaceDisplayGridExpiration source, VolSurfaceDisplayGridExpiration dest, VolSurfaceDisplayGridColumn col) {
|
||||
void _copy(
|
||||
VolSurfaceDisplayGridExpiration source,
|
||||
VolSurfaceDisplayGridExpiration dest,
|
||||
VolSurfaceDisplayGridColumn col
|
||||
) {
|
||||
if (!col.type.is_editable()) {
|
||||
throw new ArgumentException("Expected col to be editable", nameof(col));
|
||||
}
|
||||
if (current_grid.read(source, col, out var value)) {
|
||||
current_grid.set_grid_data(dest, col.unique_col_name, value);
|
||||
}
|
||||
@@ -317,7 +349,7 @@
|
||||
model.set_candidate_grid(current_grid);
|
||||
|
||||
class ColumnsModel : IDisposable {
|
||||
IDisposable _dispose;
|
||||
IDisposable? _dispose;
|
||||
|
||||
public ColumnsModel(VolSurfaceColumn row_header_col) {
|
||||
views_with_header_ro = ObservableAutoWrapper.create_read_only_wrapper(views_with_header);
|
||||
|
||||
@@ -1,335 +0,0 @@
|
||||
namespace mbts.spark.VolSurface {
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.utility;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
public struct VolSurfaceCellState {
|
||||
public bool is_dirty => committed_text != null;
|
||||
public FormattedText text;
|
||||
public FormattedText committed_text;
|
||||
}
|
||||
|
||||
class VolSurfaceRowContext : DisposableViewModelBase, ISelectable, IFormatCellsToClipboard, DIYGrid.IRowVM {
|
||||
readonly VolSurfaceGridVM _parent;
|
||||
readonly VolSurfaceDisplayGridExpiration _exp;
|
||||
/// TODO: remove _text_cache when we are sure that the new row view
|
||||
/// (<see cref="VolSurfaceRowView"/>) is solid. It must remain in place
|
||||
/// until then, as it is used by old row view
|
||||
/// (<see cref="VolSurfaceRowControl"/>).
|
||||
readonly Dictionary<string, CellData> _cells = new();
|
||||
|
||||
MenuContext _context_menu;
|
||||
bool _is_selected;
|
||||
|
||||
public VolSurfaceRowContext(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
|
||||
_parent = parent;
|
||||
_exp = exp;
|
||||
_dispose = Disposable.Create(() => {
|
||||
_cells.Values.DisposeAll();
|
||||
_cells.Clear();
|
||||
});
|
||||
}
|
||||
|
||||
public event Action<bool> is_selected_changed;
|
||||
public event Action invalidated;
|
||||
|
||||
public VolSurfaceDisplayGridExpiration expiration => _exp;
|
||||
|
||||
public bool is_selected {
|
||||
get => _is_selected;
|
||||
set {
|
||||
if (_is_selected != value) {
|
||||
_is_selected = value;
|
||||
is_selected_changed?.Invoke(value);
|
||||
_parent.signal_selection_changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MenuContext context_menu =>
|
||||
_context_menu ??= new(_parent, this);
|
||||
|
||||
public VolGridCellVM get_cell(VolSurfaceDisplayGridColumn column) {
|
||||
if (!_cells.TryGetValue(column.unique_col_name, out var cell_data)) {
|
||||
_cells.Add(column.unique_col_name, cell_data = _create_cell(column));
|
||||
}
|
||||
return cell_data.vm;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
foreach (var cell in _cells.Values) {
|
||||
_sync_cell(cell.vm);
|
||||
}
|
||||
raise_invalidated();
|
||||
}
|
||||
|
||||
public override string ToString() =>
|
||||
_exp.ToString();
|
||||
|
||||
public string[] get_cell_clipboard_strings() =>
|
||||
new[] { _exp.ToString() }.Concat(
|
||||
_parent.columns.OfType<VolSurfaceColumn>()
|
||||
.Skip(1)
|
||||
.Select(c => {
|
||||
var val = _parent.current_grid.read(_exp, c.model.unique_col_name);
|
||||
return c.model.format(val);
|
||||
}))
|
||||
.ToArray();
|
||||
|
||||
public void raise_invalidated() =>
|
||||
invalidated?.Invoke();
|
||||
|
||||
CellData _create_cell(VolSurfaceDisplayGridColumn column) {
|
||||
var cell = column.type switch {
|
||||
VolSurfaceColumnType.ReadWriteTick => create_tick_cell(),
|
||||
_ => new VolGridCellVM(column.unique_col_name),
|
||||
};
|
||||
_sync_cell(cell);
|
||||
var dispose = cell.observe_candidate().DistinctUntilChanged().OnDispatcher().Subscribe(value => {
|
||||
var curr = _parent.current_grid.read(expiration, column);
|
||||
if (Equals(value, curr)) {
|
||||
return;
|
||||
}
|
||||
var grid = _parent.current_grid;
|
||||
grid.write(expiration, column, value);
|
||||
_parent.model.set_candidate_grid(grid);
|
||||
});
|
||||
return new(cell, dispose);
|
||||
|
||||
VolGridTickCellVM create_tick_cell() {
|
||||
var cell = new VolGridTickCellVM(column.unique_col_name);
|
||||
cell.request_tick += is_up => {
|
||||
var col = _parent.get_column(column.unique_col_name);
|
||||
if (col is null) {
|
||||
throw new InvalidOperationException($"Failed to find column with id {column.unique_col_name}");
|
||||
}
|
||||
if (col.model?.tick_move is var tm) {
|
||||
cell.candidate_value = tm(cell.candidate_value, is_up);
|
||||
return;
|
||||
}
|
||||
throw new InvalidOperationException($"tick_move is not defined");
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
|
||||
void _sync_cell(VolGridCellVM cell) {
|
||||
if (cell is null) {
|
||||
return;
|
||||
}
|
||||
cell.committed_value = _parent.committed_grid.read(_exp, cell.column_id);
|
||||
cell.candidate_value = _parent.current_grid.read(_exp, cell.column_id);
|
||||
}
|
||||
|
||||
public class MenuContext : ViewModelBase {
|
||||
readonly VolSurfaceRowContext _row;
|
||||
readonly VolSurfaceGridVM _parent;
|
||||
|
||||
VolSurfaceColumn _col;
|
||||
DIYGridSuperHeaderVM _supercol;
|
||||
|
||||
ICommand _revert_command;
|
||||
ICommand _shift_selection_command;
|
||||
ICommand _shift_masters_command;
|
||||
ICommand _shift_all_command;
|
||||
ICommand _clear_command;
|
||||
ICommand _copy_to_selection_command;
|
||||
ICommand _copy_to_masters_command;
|
||||
ICommand _copy_to_all_command;
|
||||
ICommand _copy_all_to_clipboard_command;
|
||||
ICommand _smart_copy_rolls_rates_command;
|
||||
ICommand _import_csv_command;
|
||||
|
||||
public MenuContext(
|
||||
VolSurfaceGridVM parent,
|
||||
VolSurfaceRowContext row) {
|
||||
_parent = parent;
|
||||
_row = row;
|
||||
}
|
||||
|
||||
public string column_name => _col.model.display_name;
|
||||
public string group_name => _supercol.id;
|
||||
public string expiration_name => _row.ToString();
|
||||
public VolSurfaceColumn column {
|
||||
get => _col;
|
||||
set => Set(ref _col, value);
|
||||
}
|
||||
public DIYGridSuperHeaderVM super_header {
|
||||
get => _supercol;
|
||||
set => Set(ref _supercol, value);
|
||||
}
|
||||
public VolSurfaceDisplayGridExpiration expiration => _row.expiration;
|
||||
|
||||
public class SymbolFilter {
|
||||
readonly MenuContext _context;
|
||||
bool? _visible;
|
||||
|
||||
public SymbolFilter(MenuContext context, string symbol, int count, int visible_count) {
|
||||
_context = context;
|
||||
this.symbol = symbol;
|
||||
if (count == visible_count) {
|
||||
_visible = true;
|
||||
} else if (visible_count == 0) {
|
||||
_visible = false;
|
||||
} else {
|
||||
_visible = null;
|
||||
}
|
||||
}
|
||||
|
||||
public string symbol { get; private set; }
|
||||
public bool? visible {
|
||||
get => _visible;
|
||||
set {
|
||||
_visible = value;
|
||||
if (value == true) {
|
||||
_context._show_symbol(symbol);
|
||||
} else if (value == false) {
|
||||
_context._hide_symbol(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<SymbolFilter> symbols {
|
||||
get {
|
||||
var visible_exps = _parent.visible_rows
|
||||
.Cast<VolSurfaceRowContext>()
|
||||
.GroupBy(r => r._exp.symbol)
|
||||
.ToDictionary(g => g.Key);
|
||||
var result = _parent.rows
|
||||
.GroupBy(r => r._exp.symbol)
|
||||
.OrderBy(g => g.Key)
|
||||
.Select(g => new SymbolFilter(this, g.Key, g.Count(), visible_exps.ContainsKey(g.Key) ? visible_exps[g.Key].Count() : 0));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public bool is_input_cell => _col.type == VolSurfaceColumnType.ReadWriteTick;
|
||||
|
||||
public ICommand main_settings_command => _parent.main_settings_command;
|
||||
public ICommand advanced_settings_command => _parent.advanced_settings_command;
|
||||
public ICommand grid_settings_command => _parent.grid_settings_command;
|
||||
public ICommand graph_settings_command => _parent.graph_settings_command;
|
||||
|
||||
public ICommand revert_command =>
|
||||
_revert_command ??= new DelegateCommand(_ => _row.get_cell(_col.model)?.revert());
|
||||
|
||||
public ICommand shift_selection_command =>
|
||||
_shift_selection_command ??= new DelegateCommand(() => {
|
||||
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
|
||||
_parent.shift_selection(_col.model);
|
||||
}
|
||||
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
|
||||
|
||||
public ICommand shift_masters_command =>
|
||||
_shift_masters_command ??= new DelegateCommand(() => {
|
||||
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
|
||||
_parent.shift_masters(_col.model);
|
||||
}
|
||||
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
|
||||
|
||||
public ICommand shift_all_command =>
|
||||
_shift_all_command ??= new DelegateCommand(() => {
|
||||
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
|
||||
_parent.shift_all(_col.model);
|
||||
}
|
||||
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
|
||||
|
||||
public ICommand clear_command =>
|
||||
_clear_command ??= new DelegateCommand<string>(where => {
|
||||
if (Enum.TryParse(where, out GridColumnSet gc)) {
|
||||
_parent.clear(_col.model, gc);
|
||||
}
|
||||
},
|
||||
_has_editable_cells);
|
||||
|
||||
public ICommand copy_to_selection_command =>
|
||||
_copy_to_selection_command ??= new DelegateCommand<string>(where => {
|
||||
if (Enum.TryParse(where, out GridColumnSet gc)) {
|
||||
_parent.copy_to_selection(expiration, _col.model, gc);
|
||||
}
|
||||
},
|
||||
_has_editable_cells);
|
||||
|
||||
public ICommand copy_to_masters_command =>
|
||||
_copy_to_masters_command ??= new DelegateCommand<string>(where => {
|
||||
if (Enum.TryParse(where, out GridColumnSet gc)) {
|
||||
_parent.copy_to_masters(expiration, _col.model, gc);
|
||||
}
|
||||
},
|
||||
_has_editable_cells);
|
||||
|
||||
public ICommand copy_to_all_command =>
|
||||
_copy_to_all_command ??= new DelegateCommand<string>(where => {
|
||||
if (Enum.TryParse(where, out GridColumnSet gc)) {
|
||||
_parent.copy_to_all(expiration, _col.model, gc);
|
||||
}
|
||||
},
|
||||
_has_editable_cells);
|
||||
|
||||
public ICommand copy_all_to_clipboard_command =>
|
||||
_copy_all_to_clipboard_command ??= new DelegateCommand(() => {
|
||||
string clipboard_text = ClipboardHelper.GetExcelFormattedText(
|
||||
_parent.visible_rows
|
||||
.OfType<VolSurfaceRowContext>()
|
||||
.Select(r => r.get_cell_clipboard_strings())
|
||||
.Where(cells => cells != null));
|
||||
if (!clipboard_text.is_null_or_empty()) {
|
||||
ClipboardHelper.CopyTextToClipboard(clipboard_text);
|
||||
}
|
||||
});
|
||||
|
||||
public ICommand smart_copy_rolls_rates_command =>
|
||||
_smart_copy_rolls_rates_command ??= new DelegateCommand(_ => _parent.model.sync_slave_ref_forwards(expiration.ToVSExp()));
|
||||
|
||||
public ICommand import_csv_command =>
|
||||
_import_csv_command ??= FileDialogCommand.open_file(
|
||||
_parent.model.import_csv_file,
|
||||
() => _parent.model.csv_importing_enabled(),
|
||||
null);
|
||||
|
||||
bool _has_editable_cells(string where) =>
|
||||
!Enum.TryParse(where, out GridColumnSet gc) ||
|
||||
gc == GridColumnSet.Column || _col.model.type != VolSurfaceColumnType.ReadOnly;
|
||||
|
||||
void _hide_symbol(string symbol) {
|
||||
_parent.visible_rows.RemoveAll(s => ((VolSurfaceRowContext)s).expiration.symbol == symbol);
|
||||
_parent.signal_selection_changed();
|
||||
}
|
||||
|
||||
void _show_symbol(string symbol) {
|
||||
// Insert items from rows to visible_Rows that have symbol=true in sorted order
|
||||
// do this by making the desired collection and then leveraging sync_with
|
||||
var visible = new HashSet<VolSurfaceDisplayGridExpiration>(_parent.visible_rows.Cast<VolSurfaceRowContext>().Select(row => row.expiration));
|
||||
var desired = _parent.rows.Where(row => row.expiration.symbol == symbol || visible.Contains(row.expiration));
|
||||
_parent.visible_rows.sync_with(desired);
|
||||
}
|
||||
}
|
||||
|
||||
class CellData : IDisposable {
|
||||
IDisposable _dispose;
|
||||
VolGridCellVM _vm;
|
||||
|
||||
public CellData(VolGridCellVM vm, IDisposable dispose) {
|
||||
_vm = vm;
|
||||
_dispose = dispose;
|
||||
}
|
||||
|
||||
public VolGridCellVM vm => _vm;
|
||||
|
||||
public void Dispose() {
|
||||
Disposable.dispose(ref _vm);
|
||||
Disposable.dispose(ref _dispose);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using bts.collections;
|
||||
|
||||
using mbts.spark.VolSurface;
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.utility;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
class VolSurfaceRowContextMenuVM : DisposableViewModelBase {
|
||||
readonly VolSurfaceRowVM _row;
|
||||
readonly VolSurfaceGridVM _parent;
|
||||
readonly Property<VolSurfaceColumn?> _column;
|
||||
readonly Property<DIYGridSuperHeaderVM?> _super_header;
|
||||
|
||||
ICommand? _revert_cmd;
|
||||
ICommand? _shift_selection_cmd;
|
||||
ICommand? _shift_masters_cmd;
|
||||
ICommand? _shift_all_cmd;
|
||||
ICommand? _clear_cmd;
|
||||
ICommand? _copy_to_selection_cmd;
|
||||
ICommand? _copy_to_masters_cmd;
|
||||
ICommand? _copy_to_all_cmd;
|
||||
ICommand? _copy_all_to_clipboard_cmd;
|
||||
ICommand? _smart_copy_rolls_rates_cmd;
|
||||
ICommand? _import_csv_cmd;
|
||||
|
||||
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row) {
|
||||
_parent = parent;
|
||||
_row = row;
|
||||
_column = backing<VolSurfaceColumn?>(nameof(column));
|
||||
_super_header = backing<DIYGridSuperHeaderVM?>(nameof(super_header));
|
||||
|
||||
_dispose = Disposable.Create(
|
||||
_column.invalidate_others_on_change(nameof(column_name)),
|
||||
_super_header.invalidate_others_on_change(nameof(group_name)),
|
||||
_parent.visible_rows.ObserveSelf()
|
||||
.BufferLatest(TimeSpan.FromSeconds(1))
|
||||
.OnDispatcher()
|
||||
.Subscribe(_ => sync_symbols()));
|
||||
|
||||
void sync_symbols() {
|
||||
var visible_exps = _parent.visible_rows.Map(r => r.expiration.symbol);
|
||||
symbols.sync_with_models(
|
||||
visible_exps,
|
||||
kv => new SymbolItemVM(this, kv.Key),
|
||||
(svm, kv) => {
|
||||
svm.symbol = kv.Key;
|
||||
svm.visible = SelectAllToggle.is_all_selected(
|
||||
visible_exps[svm.symbol].Count(),
|
||||
kv.Value.Count());
|
||||
return svm;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public string column_name => column?.model?.display_name ?? string.Empty;
|
||||
public string group_name => super_header?.id ?? string.Empty;
|
||||
public string expiration_name => _row.ToString();
|
||||
public VolSurfaceColumn? column {
|
||||
get => _column.Value;
|
||||
set => _column.set(value);
|
||||
}
|
||||
public DIYGridSuperHeaderVM? super_header {
|
||||
get => _super_header.Value;
|
||||
set => _super_header.set(value);
|
||||
}
|
||||
public VolSurfaceDisplayGridExpiration expiration => _row.expiration;
|
||||
|
||||
public ObservableCollection<SymbolItemVM> symbols { get; } = new();
|
||||
|
||||
public bool is_input_cell => column?.type == VolSurfaceColumnType.ReadWriteTick;
|
||||
|
||||
public ICommand populate_empty_exps_cmd => _parent.populate_empty_exps_cmd;
|
||||
public ICommand main_settings_cmd => _parent.main_settings_cmd;
|
||||
public ICommand advanced_settings_cmd => _parent.advanced_settings_cmd;
|
||||
public ICommand grid_settings_cmd => _parent.grid_settings_cmd;
|
||||
public ICommand graph_settings_cmd => _parent.graph_settings_cmd;
|
||||
|
||||
public ICommand revert_cmd =>
|
||||
_revert_cmd ??= new Command(_ => {
|
||||
_row.get_cell(_assert_model())?.revert();
|
||||
});
|
||||
|
||||
public ICommand shift_selection_cmd =>
|
||||
_shift_selection_cmd ??= new Command(() => {
|
||||
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
|
||||
_parent.shift_selection(_assert_model());
|
||||
}
|
||||
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
|
||||
|
||||
public ICommand shift_masters_cmd =>
|
||||
_shift_masters_cmd ??= new Command(() => {
|
||||
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
|
||||
_parent.shift_masters(_assert_model());
|
||||
}
|
||||
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
|
||||
|
||||
public ICommand shift_all_cmd =>
|
||||
_shift_all_cmd ??= new Command(() => {
|
||||
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
|
||||
_parent.shift_all(_assert_model());
|
||||
}
|
||||
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
|
||||
|
||||
public ICommand clear_cmd =>
|
||||
_clear_cmd ??= new Command<string>(where => {
|
||||
if (Enum.TryParse(where, out GridColumnSet gc)) {
|
||||
_parent.clear(_assert_model(), gc);
|
||||
}
|
||||
},
|
||||
_has_editable_cells);
|
||||
|
||||
public ICommand copy_to_selection_cmd =>
|
||||
_copy_to_selection_cmd ??= new Command<string>(where => {
|
||||
if (Enum.TryParse(where, out GridColumnSet gc)) {
|
||||
_parent.copy_to_selection(expiration, _assert_model(), gc);
|
||||
}
|
||||
});
|
||||
|
||||
public ICommand copy_to_masters_cmd =>
|
||||
_copy_to_masters_cmd ??= new Command<string>(where => {
|
||||
if (Enum.TryParse(where, out GridColumnSet gc)) {
|
||||
_parent.copy_to_masters(expiration, _assert_model(), gc);
|
||||
}
|
||||
});
|
||||
|
||||
public ICommand copy_to_all_cmd =>
|
||||
_copy_to_all_cmd ??= new Command<string>(where => {
|
||||
if (Enum.TryParse(where, out GridColumnSet gc)) {
|
||||
_parent.copy_to_all(expiration, _assert_model(), gc);
|
||||
}
|
||||
});
|
||||
|
||||
public ICommand copy_all_to_clipboard_cmd =>
|
||||
_copy_all_to_clipboard_cmd ??= new Command(() => {
|
||||
string clipboard_text = ClipboardHelper.GetExcelFormattedText(
|
||||
_parent.visible_rows
|
||||
.OfType<VolSurfaceRowVM>()
|
||||
.Select(r => r.get_cell_clipboard_strings())
|
||||
.Where(cells => cells != null));
|
||||
if (!clipboard_text.is_null_or_empty()) {
|
||||
ClipboardHelper.CopyTextToClipboard(clipboard_text);
|
||||
}
|
||||
});
|
||||
|
||||
public ICommand smart_copy_rolls_rates_cmd =>
|
||||
_smart_copy_rolls_rates_cmd ??= new Command(
|
||||
() => _parent.model.sync_slave_ref_forwards(expiration.ToVSExp()));
|
||||
|
||||
public ICommand import_csv_cmd =>
|
||||
_import_csv_cmd ??= FileDialogCommand.open_file(
|
||||
_parent.model.import_csv_file,
|
||||
_parent.model.csv_importing_enabled,
|
||||
null);
|
||||
|
||||
VolSurfaceDisplayGridColumn _assert_model() =>
|
||||
column?.model ?? throw new InvalidOperationException();
|
||||
|
||||
bool _has_editable_cells(string where) =>
|
||||
!Enum.TryParse(where, out GridColumnSet gc) ||
|
||||
gc == GridColumnSet.Column || _assert_model().type != VolSurfaceColumnType.ReadOnly;
|
||||
|
||||
void _hide_symbol(string symbol) {
|
||||
_parent.visible_rows.RemoveAll(s => s.expiration.symbol == symbol);
|
||||
_parent.signal_selection_changed();
|
||||
}
|
||||
|
||||
void _show_symbol(string symbol) {
|
||||
// Insert items from rows to visible_Rows that have symbol=true in sorted order
|
||||
// do this by making the desired collection and then leveraging sync_with
|
||||
var visible = _parent.visible_rows
|
||||
.Select(row => row.expiration)
|
||||
.ToHashSet();
|
||||
var desired = _parent.rows.Where(
|
||||
row => row.expiration.symbol == symbol || visible.Contains(row.expiration));
|
||||
_parent.visible_rows.sync_with(desired);
|
||||
}
|
||||
|
||||
public class SymbolItemVM : ViewModelBase {
|
||||
readonly VolSurfaceRowContextMenuVM _context;
|
||||
string _symbol;
|
||||
bool? _visible;
|
||||
|
||||
public SymbolItemVM(
|
||||
VolSurfaceRowContextMenuVM context, string symbol) {
|
||||
_context = context;
|
||||
_symbol = symbol;
|
||||
}
|
||||
|
||||
public string symbol {
|
||||
get => _symbol;
|
||||
set => Set(ref _symbol, value);
|
||||
}
|
||||
|
||||
public bool? visible {
|
||||
get => _visible;
|
||||
set {
|
||||
if (Set(ref _visible, value)) {
|
||||
if (value is true) {
|
||||
_context._show_symbol(symbol);
|
||||
} else if (value is false) {
|
||||
_context._hide_symbol(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,372 +0,0 @@
|
||||
// using mbts;
|
||||
// using mbts.ui;
|
||||
// using mbts.ui.controls;
|
||||
// using mbts.ui.dpi;
|
||||
// using mbts.ui.utility.text;
|
||||
|
||||
// using System;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Diagnostics;
|
||||
// using System.Globalization;
|
||||
// using System.Linq;
|
||||
// using System.Text;
|
||||
// using System.Threading.Tasks;
|
||||
// using System.Windows;
|
||||
// using System.Windows.Controls;
|
||||
// using System.Windows.Input;
|
||||
// using System.Windows.Media;
|
||||
|
||||
// namespace mbts.spark.VolSurface {
|
||||
// class VolSurfaceRowControl : DIYGrid.HighPerformanceRow<VolSurfaceRowContext> {
|
||||
// FormattedText _exp_text;
|
||||
// readonly double _padding = 5.0;
|
||||
// readonly Pen _dirty_pen = new Pen(Brushes.Red, 1.0);
|
||||
// readonly Pen _selection_pen = new Pen(Brushes.Black, 1.0) { DashStyle = DashStyles.Dot };
|
||||
|
||||
// TickUpDown _cell_editor_backing;
|
||||
// TickUpDown _cell_editor => _cell_editor_backing ??= new ();
|
||||
|
||||
// int? _selected_cell;
|
||||
|
||||
// public VolSurfaceRowControl() {
|
||||
// Loaded += (s, e) => ContextMenu = TryFindResource("context_menu") as ContextMenu;
|
||||
// GotKeyboardFocus += (s, e) => {
|
||||
// if (e.OriginalSource is not FrameworkElement el) {
|
||||
// return;
|
||||
// }
|
||||
// var cell_tl = el.TranslatePoint(new Point(0, 0), this);
|
||||
// _on_focus_move(DIYGrid.RowUtils.column_at(_column_layout, cell_tl));
|
||||
// };
|
||||
// }
|
||||
|
||||
// int? _column_index(DIYGrid.ColumnGeometry col) =>
|
||||
// _column_layout.TryGetFirst(c => c.Equals(col), out var _, out var idx) ? idx : null;
|
||||
|
||||
// //private static int _render_count = 0;
|
||||
// protected override void OnRender(DrawingContext dc) {
|
||||
// // Fill with transparent for hit testing
|
||||
// dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, new Rect(0, 0, _column_layout.Sum(c => c.width), RenderSize.Height));
|
||||
|
||||
// string last_group = "";
|
||||
// foreach (var cell in _column_layout) {
|
||||
// // Render collapsed columns
|
||||
// if (cell.column.is_collapsed) {
|
||||
// dc.DrawRectangle(BTSColors.AW2.collapsed, null, new Rect(cell.left, 0, cell.width, Height));
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// var column = (VolSurfaceSimplifiedColumn)cell.column;
|
||||
// VolSurfaceCellState celldata;
|
||||
|
||||
// // Get the cell text
|
||||
// if (column.type == VolSurfaceSimplifiedColumnType.RowHeader) {
|
||||
// // Fill in this one
|
||||
// dc.DrawRectangle(BTSColors.header, null, new Rect(cell.left, 0, cell.width, Height));
|
||||
// var exp = _row.expiration;
|
||||
// if (_exp_text == null) {
|
||||
// _exp_text = format_text(exp.ToString(), exp.is_slave ? Brushes.LightGray : Brushes.White);
|
||||
// }
|
||||
// celldata = new VolSurfaceCellState() {
|
||||
// text = _exp_text
|
||||
// };
|
||||
// } else if (column.type == VolSurfaceSimplifiedColumnType.ReadOnly) {
|
||||
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Blue), _ => null);
|
||||
// } else {
|
||||
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Black), format(Brushes.DarkGray));
|
||||
// }
|
||||
|
||||
// // If the cell is partly hidden clip the draw
|
||||
// if (cell.is_partially_obscured) {
|
||||
// dc.PushClip(new RectangleGeometry(
|
||||
// new Rect(cell.left, 0, cell.width, Height)));
|
||||
// }
|
||||
|
||||
// // draw text centered vertially
|
||||
// double total_width = _padding + celldata.text.Width;
|
||||
// double pad_top = (Height - celldata.text.Height) / 2.0;
|
||||
// dc.DrawText(celldata.text, new Point(cell.unclipped_left + _padding, pad_top));
|
||||
// if (celldata.committed_text != null) {
|
||||
// pad_top = (Height - celldata.committed_text.Height) / 2.0;
|
||||
// dc.DrawText(celldata.committed_text, new Point(cell.unclipped_left + total_width, pad_top));
|
||||
// total_width += celldata.committed_text.Width;
|
||||
// }
|
||||
|
||||
// // draw grid lines
|
||||
// double line_width; Brush fill;
|
||||
// if (last_group == cell.group) { line_width = 1; fill = _grid.VerticalGridLineBrush; } else { line_width = 2; fill = _grid.VerticalGroupSeparatorBrush; }
|
||||
// dc.DrawRectangle(fill, null, new Rect(cell.left - line_width, 0, line_width, Height));
|
||||
// Rect cell_border_rect = new Rect(cell.unclipped_left + 1, 0, Math.Max(0, cell.width - (line_width * 2)), Height - 1);
|
||||
// // draw dirty rect
|
||||
// if (celldata.is_dirty) {
|
||||
// dc.DrawRectangle(null, _dirty_pen, cell_border_rect);
|
||||
// }
|
||||
|
||||
// // Draw selection
|
||||
// if (_selected_cell == _column_index(cell) && column.type != VolSurfaceSimplifiedColumnType.ReadWriteTick) {
|
||||
// dc.DrawRectangle(null, _selection_pen, cell_border_rect);
|
||||
// }
|
||||
|
||||
// if (cell.is_partially_obscured) { dc.Pop(); }
|
||||
|
||||
// total_width += _padding;//right padding
|
||||
// if (!celldata.is_dirty && column.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) total_width += 22; // size of buttons on a tickupdown
|
||||
// if (total_width > cell.width) {
|
||||
// Dispatcher.BeginInvoke(((Action)(() => cell.column.Width = total_width)));
|
||||
// }
|
||||
// last_group = cell.group;
|
||||
// }
|
||||
|
||||
// if (_selected_cell != NO_CELL) {
|
||||
// if (_cell_editor.Visibility == Visibility.Visible) {
|
||||
// var position = _column_geometry[_selected_cell];
|
||||
// PositionControlOver(tud, position);
|
||||
// }
|
||||
// }
|
||||
|
||||
// //++_render_count;
|
||||
// //dc.DrawText(
|
||||
// // format_text(_render_count.ToString(), Brushes.Black),
|
||||
// // new Point(0, 0));
|
||||
// }
|
||||
|
||||
// Func<string, FormattedText> format(Brush brush) =>
|
||||
// str => format_text(str, brush);
|
||||
|
||||
// void _on_focus_move(DIYGrid.ColumnGeometry? new_column) {
|
||||
// if (new_column != null) {
|
||||
// enable_edit(new_column.Value);
|
||||
// }
|
||||
// InvalidateVisual();
|
||||
// }
|
||||
|
||||
// private async void enable_edit(DIYGrid.ColumnGeometry column) {
|
||||
// await Task.Yield();
|
||||
// var col = (VolSurfaceSimplifiedColumn)column.column;
|
||||
// var tud = _grid.get_edit_control<TickUpDown>();
|
||||
// if (col.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) {
|
||||
// tud.DataContext = _row.get_edit_context(col.volsurface_column);
|
||||
// PositionControlOver(tud, column);
|
||||
// var fe = tud.Content as TextBox;
|
||||
// if (fe != null) {
|
||||
// await Task.Yield();
|
||||
// fe.Focus();
|
||||
// fe.SelectAll();
|
||||
// }
|
||||
// } else {
|
||||
// tud.DataContext = null;
|
||||
// tud.Visibility = Visibility.Collapsed;
|
||||
// var item = this.find_ancestor_of_type<ListBoxItem>();
|
||||
// if (item != null) {
|
||||
// item.Focus();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) {
|
||||
// // _grid.column
|
||||
// var cell = DIYGrid.RowUtils.column_at(_column_layout, e.GetPosition(this));
|
||||
// if (ContextMenu != null) {
|
||||
// if (cell.HasValue && DIYGrid.RowUtils.column_index(_column_layout, cell.Value) > (_grid.FrozenColumnCount - 1)) {
|
||||
// ContextMenu.DataContext = _row.get_context_menu_context((VolSurfaceSimplifiedColumn)cell.Value.column, cell.Value.super_column);
|
||||
// } else {
|
||||
// e.Handled = true;
|
||||
// ContextMenu.DataContext = null;
|
||||
// }
|
||||
// }
|
||||
// base.OnMouseRightButtonDown(e);
|
||||
// }
|
||||
|
||||
// FormattedText format_text(string content, Brush fg) {
|
||||
// var ft = new FormattedText(content, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
|
||||
// TextUtils.StandardTypeface, FontSizes.Regular, Brushes.Black, HighDpiExtensions.dpi_ratio);
|
||||
// return ft;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// using mbts;
|
||||
// using mbts.ui;
|
||||
// using mbts.ui.controls;
|
||||
// using mbts.ui.dpi;
|
||||
// using mbts.ui.utility.text;
|
||||
|
||||
// using System;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Diagnostics;
|
||||
// using System.Globalization;
|
||||
// using System.Linq;
|
||||
// using System.Text;
|
||||
// using System.Threading.Tasks;
|
||||
// using System.Windows;
|
||||
// using System.Windows.Controls;
|
||||
// using System.Windows.Input;
|
||||
// using System.Windows.Media;
|
||||
|
||||
// namespace mbts.spark.VolSurface {
|
||||
// class VolSurfaceRowControl : DIYGrid.RowBase {
|
||||
// VolSurfaceRowContext _row;
|
||||
// FormattedText _exp_text;
|
||||
// readonly double _padding = 5.0;
|
||||
// readonly Pen _dirty_pen = new Pen(Brushes.Red, 1.0);
|
||||
// readonly Pen _selection_pen = new Pen(Brushes.Black, 1.0) { DashStyle = DashStyles.Dot };
|
||||
|
||||
// public VolSurfaceRowControl() {
|
||||
// DataContextChanged += OnDataContextChanged;
|
||||
// Loaded += OnLoaded;
|
||||
// }
|
||||
|
||||
// #region SelectedCell
|
||||
// public static readonly DependencyProperty SelectedCellProperty =
|
||||
// WPFHelper.create_dp<object, VolSurfaceRowControl>(nameof(SelectedCell));
|
||||
|
||||
// public object SelectedCell {
|
||||
// get => GetValue(SelectedCellProperty);
|
||||
// set => SetValue(SelectedCellProperty, value);
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
// void OnLoaded(object sender, RoutedEventArgs e) {
|
||||
// ContextMenu = TryFindResource("context_menu") as ContextMenu;
|
||||
// }
|
||||
|
||||
// void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) {
|
||||
// var oldrow = e.OldValue as VolSurfaceRowContext;
|
||||
// if (oldrow != null) {
|
||||
// oldrow.on_invalidate -= InvalidateVisual;
|
||||
// }
|
||||
// _row = DataContext as VolSurfaceRowContext;
|
||||
// _row.on_invalidate += InvalidateVisual;
|
||||
// }
|
||||
|
||||
// //private static int _render_count = 0;
|
||||
// protected override void OnRender(DrawingContext dc) {
|
||||
// if (_grid == null) return;
|
||||
// // Fill with transparent for hit testing
|
||||
// dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, new Rect(0, 0, _column_geometry.Sum(g => g.width), RenderSize.Height));
|
||||
|
||||
// string last_group = "";
|
||||
// foreach (var cell in _column_geometry) {
|
||||
// // Render collapsed columns
|
||||
// if (cell.column.is_collapsed) {
|
||||
// dc.DrawRectangle(BTSColors.AW2.collapsed, null, new Rect(cell.left, 0, cell.width, Height));
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// var column = (VolSurfaceSimplifiedColumn)cell.column;
|
||||
// VolSurfaceCellState celldata;
|
||||
|
||||
// // Get the cell text
|
||||
// if (column.type == VolSurfaceSimplifiedColumnType.RowHeader) {
|
||||
// // Fill in this one
|
||||
// dc.DrawRectangle(BTSColors.header, null, new Rect(cell.left, 0, cell.width, Height));
|
||||
// var exp = _row.expiration;
|
||||
// if (_exp_text == null) {
|
||||
// _exp_text = format_text(exp.ToString(), exp.is_slave ? Brushes.LightGray : Brushes.White);
|
||||
// }
|
||||
// celldata = new VolSurfaceCellState() { text = _exp_text };
|
||||
// } else if (column.type == VolSurfaceSimplifiedColumnType.ReadOnly) {
|
||||
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Blue), _ => null);
|
||||
// } else {
|
||||
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Black), format(Brushes.DarkGray));
|
||||
// }
|
||||
|
||||
// // If the cell is partly hidden clip the draw
|
||||
// if (cell.is_partially_obscured) {
|
||||
// dc.PushClip(new RectangleGeometry(
|
||||
// new Rect(cell.left, 0, cell.width, Height)));
|
||||
// }
|
||||
|
||||
// // draw text centered vertially
|
||||
// double total_width = _padding + celldata.text.Width;
|
||||
// double pad_top = (Height - celldata.text.Height) / 2.0;
|
||||
// dc.DrawText(celldata.text, new Point(cell.unclipped_left + _padding, pad_top));
|
||||
// if (celldata.committed_text != null) {
|
||||
// pad_top = (Height - celldata.committed_text.Height) / 2.0;
|
||||
// dc.DrawText(celldata.committed_text, new Point(cell.unclipped_left + total_width, pad_top));
|
||||
// total_width += celldata.committed_text.Width;
|
||||
// }
|
||||
|
||||
// // draw grid lines
|
||||
// double line_width; Brush fill;
|
||||
// if (last_group == cell.group) { line_width = 1; fill = _grid.VerticalGridLineBrush; } else { line_width = 2; fill = _grid.VerticalGroupSeparatorBrush; }
|
||||
// dc.DrawRectangle(fill, null, new Rect(cell.left - line_width, 0, line_width, Height));
|
||||
// Rect cell_border_rect = new Rect(cell.unclipped_left + 1, 0, Math.Max(0, cell.width - (line_width * 2)), Height - 1);
|
||||
// // draw dirty rect
|
||||
// if (celldata.is_dirty) {
|
||||
// dc.DrawRectangle(null, _dirty_pen, cell_border_rect);
|
||||
// }
|
||||
|
||||
// // Draw selection
|
||||
// if (_selected_cell == column_index(cell) && column.type != VolSurfaceSimplifiedColumnType.ReadWriteTick) {
|
||||
// dc.DrawRectangle(null, _selection_pen, cell_border_rect);
|
||||
// }
|
||||
|
||||
// if (cell.is_partially_obscured) { dc.Pop(); }
|
||||
|
||||
// total_width += _padding;//right padding
|
||||
// if (!celldata.is_dirty && column.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) total_width += 22; // size of buttons on a tickupdown
|
||||
// if (total_width > cell.width) {
|
||||
// Dispatcher.BeginInvoke(((Action)(() => cell.column.Width = total_width)));
|
||||
// }
|
||||
// last_group = cell.group;
|
||||
// }
|
||||
|
||||
// //++_render_count;
|
||||
// //dc.DrawText(
|
||||
// // format_text(_render_count.ToString(), Brushes.Black),
|
||||
// // new Point(0, 0));
|
||||
// }
|
||||
// private Func<string, FormattedText> format(Brush brush) {
|
||||
// return str => format_text(str, brush);
|
||||
// }
|
||||
// protected override void OnClick(DIYGrid.ColumnGeometry column) {
|
||||
// }
|
||||
|
||||
// protected override void OnFocusMove(DIYGrid.ColumnGeometry? new_column) {
|
||||
// if (new_column != null) enable_edit(new_column.Value);
|
||||
// InvalidateVisual();
|
||||
// }
|
||||
|
||||
// private async void enable_edit(DIYGrid.ColumnGeometry column) {
|
||||
// await Task.Yield();
|
||||
// var col = (VolSurfaceSimplifiedColumn)column.column;
|
||||
// var tud = _grid.get_edit_control<TickUpDown>();
|
||||
// if (col.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) {
|
||||
// tud.DataContext = _row.get_edit_context(col.volsurface_column);
|
||||
// PositionControlOver(tud, column);
|
||||
// var fe = tud.Content as TextBox;
|
||||
// if (fe != null) {
|
||||
// await Task.Yield();
|
||||
// fe.Focus();
|
||||
// fe.SelectAll();
|
||||
// }
|
||||
// } else {
|
||||
// tud.DataContext = null;
|
||||
// tud.Visibility = Visibility.Collapsed;
|
||||
// var item = this.find_ancestor_of_type<ListBoxItem>();
|
||||
// if (item != null) {
|
||||
// item.Focus();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) {
|
||||
// var cell = column_at(e.GetPosition(this));
|
||||
// if (ContextMenu != null) {
|
||||
// if (cell.HasValue && column_index(cell.Value) > (_grid.FrozenColumnCount - 1)) {
|
||||
// ContextMenu.DataContext = _row.get_context_menu_context((VolSurfaceSimplifiedColumn)cell.Value.column, cell.Value.super_column);
|
||||
// } else {
|
||||
// e.Handled = true;
|
||||
// ContextMenu.DataContext = null;
|
||||
// }
|
||||
// }
|
||||
// base.OnMouseRightButtonDown(e);
|
||||
// }
|
||||
|
||||
// FormattedText format_text(string content, Brush fg) {
|
||||
// var ft = new FormattedText(content, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
|
||||
// TextUtils.StandardTypeface, FontSizes.Regular, Brushes.Black, HighDpiExtensions.dpi_ratio);
|
||||
// return ft;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,149 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark.VolSurface {
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.shell;
|
||||
|
||||
using Spark.Core;
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
class VolSurfaceRowVM : DisposableViewModelBase, ISelectable, IFormatCellsToClipboard, DIYGrid.IRowVM {
|
||||
readonly VolSurfaceGridVM _parent;
|
||||
readonly VolSurfaceDisplayGridExpiration _exp;
|
||||
readonly Dictionary<string, CellData> _cells = new();
|
||||
readonly DeferrableAction _request_calculate;
|
||||
|
||||
VolSurfaceRowContextMenuVM? _context_menu;
|
||||
bool _is_selected;
|
||||
|
||||
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
|
||||
_parent = parent;
|
||||
_exp = exp;
|
||||
_request_calculate = new(() => request_calculate?.Invoke());
|
||||
_dispose = Disposable.Create(() => {
|
||||
_cells.Values.DisposeAll();
|
||||
_cells.Clear();
|
||||
_context_menu?.Dispose();
|
||||
});
|
||||
}
|
||||
|
||||
public event Action<bool>? is_selected_changed;
|
||||
public event Action? invalidated;
|
||||
public event Action? request_calculate;
|
||||
|
||||
public VolSurfaceDisplayGridExpiration expiration => _exp;
|
||||
|
||||
public bool is_selected {
|
||||
get => _is_selected;
|
||||
set {
|
||||
if (Set(ref _is_selected, value)) {
|
||||
is_selected_changed?.Invoke(value);
|
||||
_parent.signal_selection_changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public VolSurfaceRowContextMenuVM context_menu =>
|
||||
_context_menu ??= new(_parent, this);
|
||||
|
||||
public VolSurfaceCellVM get_cell(VolSurfaceDisplayGridColumn column) =>
|
||||
_cells.GetOrAdd(column.unique_col_name, _ => _create_cell(column)).vm;
|
||||
|
||||
public void invalidate() {
|
||||
using (_request_calculate.supress()) {
|
||||
foreach (var cell in _cells.Values) {
|
||||
_sync_cell(cell.vm);
|
||||
}
|
||||
}
|
||||
invalidated?.Invoke();
|
||||
}
|
||||
|
||||
public string[] get_cell_clipboard_strings() =>
|
||||
new[] { _exp.ToString() }.Concat(
|
||||
_parent.columns.OfType<VolSurfaceColumn>().Skip(1).Select(c => {
|
||||
var val = _parent.current_grid.read(_exp, c.model.unique_col_name);
|
||||
return c.model.format(val);
|
||||
}))
|
||||
.ToArray();
|
||||
|
||||
public override string ToString() =>
|
||||
_exp.ToString();
|
||||
|
||||
void DIYGrid.IRowVM.raise_invalidated() =>
|
||||
invalidated?.Invoke();
|
||||
|
||||
CellData _create_cell(VolSurfaceDisplayGridColumn column) {
|
||||
var cell = column.type switch {
|
||||
VolSurfaceColumnType.ReadWriteTick => create_tick_cell(),
|
||||
_ => new VolSurfaceCellVM(_exp, column)
|
||||
};
|
||||
_sync_cell(cell);
|
||||
return new(cell, _connect_cell(cell));
|
||||
|
||||
VolSurfaceCellVM create_tick_cell() {
|
||||
var cell = new VolSurfaceTickCellVM(_exp, column);
|
||||
cell.request_tick += is_up => {
|
||||
var col = _parent.get_column(column.unique_col_name);
|
||||
if (col.model?.tick_move is var tm) {
|
||||
cell.candidate_value = tm?.Invoke(cell.candidate_value, is_up);
|
||||
return;
|
||||
}
|
||||
throw new InvalidOperationException($"tick_move is not defined");
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
|
||||
void _sync_cell(VolSurfaceCellVM cell) {
|
||||
if (cell is null) {
|
||||
return;
|
||||
}
|
||||
using var _ = _request_calculate.supress();
|
||||
cell.reset(
|
||||
committed_value: _parent.committed_grid.read(_exp, cell.column_id),
|
||||
candidate_value: _parent.current_grid.read(_exp, cell.column_id));
|
||||
}
|
||||
|
||||
IDisposable? _connect_cell(VolSurfaceCellVM cell) {
|
||||
return cell.column.type switch {
|
||||
VolSurfaceColumnType.ReadWriteTick => connect_input(),
|
||||
_ => null
|
||||
};
|
||||
|
||||
IDisposable connect_input() {
|
||||
cell.candidate_value_changed += on_candidate_value_changed;
|
||||
return Disposable.Create(() =>
|
||||
cell.candidate_value_changed -= on_candidate_value_changed);
|
||||
|
||||
void on_candidate_value_changed(object? oldval, object? newval) {
|
||||
var curr = _parent.current_grid.read(expiration, cell.column);
|
||||
if (cell.column.comparer.Equals(newval, curr)) {
|
||||
return;
|
||||
}
|
||||
var grid = _parent.current_grid;
|
||||
grid.write(expiration, cell.column, newval);
|
||||
_request_calculate.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CellData : IDisposable {
|
||||
IDisposable? _dispose;
|
||||
|
||||
public CellData(VolSurfaceCellVM vm, IDisposable? dispose) {
|
||||
this.vm = vm;
|
||||
_dispose = Disposable.Create(vm, dispose);
|
||||
}
|
||||
|
||||
public VolSurfaceCellVM vm { get; }
|
||||
|
||||
public void Dispose() =>
|
||||
Disposable.dispose(ref _dispose);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
class VolSurfaceTickCellVM : VolSurfaceCellVM {
|
||||
ICommand? _tick_up_cmd;
|
||||
ICommand? _tick_down_cmd;
|
||||
|
||||
public VolSurfaceTickCellVM(
|
||||
VolSurfaceDisplayGridExpiration expiration, VolSurfaceDisplayGridColumn column)
|
||||
: base(expiration, column) { }
|
||||
|
||||
public event Action<bool>? request_tick;
|
||||
|
||||
public ICommand tick_up_cmd =>
|
||||
_tick_up_cmd ??= new DelegateCommand(() =>
|
||||
request_tick?.Invoke(true));
|
||||
|
||||
public ICommand tick_down_cmd =>
|
||||
_tick_down_cmd ??= new DelegateCommand(() =>
|
||||
request_tick?.Invoke(false));
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -3,6 +3,8 @@ using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.utility;
|
||||
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -21,7 +23,7 @@ namespace mbts.spark {
|
||||
if (_settings.precomputed_theo_handles == null)
|
||||
_settings.precomputed_theo_handles = new List<double>();
|
||||
vol_surface_name = vs_name;
|
||||
this.commit = new DelegateCommand(() => request_commit?.Invoke(ProtoBufSerializationHelper.clone_protobuf(_settings)));
|
||||
this.commit = new DelegateCommand(() => request_commit?.Invoke(ProtobufSerializationHelper.clone(_settings)));
|
||||
}
|
||||
|
||||
public event Action<VolSurfaceAdvancedSettings> request_commit;
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls.graph;
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace mbts.spark
|
||||
{
|
||||
class VolSurfaceGraphSettingsEditorVM
|
||||
{
|
||||
public VolSurfaceGraphSettingsEditorVM(string vol_surface_name, VolSurfaceGraphSettings settings, Action<VolSurfaceGraphSettings> commit) {
|
||||
this.vol_surface_name = vol_surface_name;
|
||||
_settings = settings;
|
||||
this.commit = new DelegateCommand(() => commit(_settings));
|
||||
}
|
||||
|
||||
private readonly VolSurfaceGraphSettings _settings;
|
||||
|
||||
public string vol_surface_name { get; private set; }
|
||||
|
||||
public VolSurfaceScatterSeriesSettingsVM implied_puts { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.implied_puts); } }
|
||||
public VolSurfaceScatterSeriesSettingsVM implied_atm { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.implied_atm); } }
|
||||
public VolSurfaceScatterSeriesSettingsVM implied_calls { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.implied_calls); } }
|
||||
|
||||
public VolSurfaceScatterSeriesSettingsVM put_control_points { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.put_control_points); } }
|
||||
public VolSurfaceScatterSeriesSettingsVM atm { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.atm); } }
|
||||
public VolSurfaceScatterSeriesSettingsVM call_control_points { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.call_control_points); } }
|
||||
|
||||
public VolSurfaceLineSeriesSettingsVM put_wing { get { return new VolSurfaceLineSeriesSettingsVM(_settings.put_wing); } }
|
||||
public VolSurfaceLineSeriesSettingsVM inner_curve { get { return new VolSurfaceLineSeriesSettingsVM(_settings.inner_curve); } }
|
||||
public VolSurfaceLineSeriesSettingsVM call_wing { get { return new VolSurfaceLineSeriesSettingsVM(_settings.call_wing); } }
|
||||
|
||||
public VolSurfaceLineSeriesSettingsVM vol_path { get { return new VolSurfaceLineSeriesSettingsVM(_settings.vol_path); } }
|
||||
|
||||
public ICommand commit { get; private set; }
|
||||
}
|
||||
|
||||
|
||||
class VolSurfaceScatterSeriesSettingsVM
|
||||
{
|
||||
public VolSurfaceScatterSeriesSettingsVM(ScatterSeriesSettings settings) {
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
private readonly ScatterSeriesSettings _settings;
|
||||
|
||||
public MarkerShape shape { get { return _settings.shape; } set { _settings.shape = value; } }
|
||||
public double size { get { return _settings.size; } set { _settings.size = value; } }
|
||||
public Color fill {
|
||||
get => _settings.fill;
|
||||
set => _settings.fill = value;
|
||||
}
|
||||
public Color stroke {
|
||||
get => _settings.stroke;
|
||||
set => _settings.stroke = value;
|
||||
}
|
||||
|
||||
public Array shapes { get { return Enum.GetValues(typeof(MarkerShape)); } }
|
||||
}
|
||||
|
||||
class VolSurfaceLineSeriesSettingsVM
|
||||
{
|
||||
public VolSurfaceLineSeriesSettingsVM(LineSeriesSettings settings) {
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
private readonly LineSeriesSettings _settings;
|
||||
|
||||
public Color color { get { return (Color)_settings.color; } set { _settings.color = (BTSColor)value; } }
|
||||
public double thickness { get { return _settings.stroke_thickness; } set { _settings.stroke_thickness = value; } }
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,9 @@ namespace mbts.spark {
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.utility;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
@@ -23,6 +26,9 @@ namespace mbts.spark {
|
||||
readonly VolSurfaceSettings _settings;
|
||||
readonly VolSurfaceCoreSettings _core_settings;
|
||||
|
||||
string _selected_section;
|
||||
bool _can_edit_name = true;
|
||||
|
||||
public VolSurfaceSettingsEditorVM(IBus bus, VolSurfaceSettings settings, Action<VolSurfaceSettings> commit) {
|
||||
if (settings is null) {
|
||||
throw new ArgumentNullException(nameof(settings));
|
||||
@@ -113,7 +119,23 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public string vol_surface_name { get { return _core_settings.vol_surface_name; } }
|
||||
public string vol_surface_name {
|
||||
get => _core_settings.vol_surface_name;
|
||||
set {
|
||||
using var _ = detect_property_change();
|
||||
_core_settings.vol_surface_name = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool can_edit_name {
|
||||
get => _can_edit_name;
|
||||
set => Set(ref _can_edit_name, value);
|
||||
}
|
||||
|
||||
public string selected_section {
|
||||
get => _selected_section;
|
||||
set => Set(ref _selected_section, value);
|
||||
}
|
||||
|
||||
public VSSymbolStructureVM symbol_structure_vm { get; set; }
|
||||
public VolModelPolynomialVM vol_model_polynomial_vm { get; } = new();
|
||||
@@ -353,7 +375,7 @@ namespace mbts.spark {
|
||||
public ICommand commit { get; }
|
||||
|
||||
public VolSurfaceSettings get_settings() {
|
||||
var rv = ProtoBufSerializationHelper.clone_protobuf(_settings);
|
||||
var rv = ProtobufSerializationHelper.clone(_settings);
|
||||
var symbols = symbol_structure_vm.driver_grids
|
||||
.SelectMany(dg => dg.symbols.Where(sym => sym.is_selected))
|
||||
.ToList();
|
||||
@@ -518,17 +540,22 @@ namespace mbts.spark {
|
||||
public ObservableCollection<VSSymbol> symbols { get; private set; }
|
||||
|
||||
public void Dispose() =>
|
||||
Disposable.dispose(symbols);
|
||||
symbols.DisposeAll(true);
|
||||
}
|
||||
|
||||
public class VSSymbolStructureVM : DisposableViewModelBase {
|
||||
readonly Property<VSSymbolGridVM> _selected_driver_grid;
|
||||
|
||||
public VSSymbolStructureVM(IBus bus, VolSurfaceSettings settings) {
|
||||
driver_grids = new ObservableCollection<VSSymbolGridVM>();
|
||||
_selected_driver_grid = backing<VSSymbolGridVM>(nameof(selected_driver_grid));
|
||||
settings.core_settings.master_slave_relationships ??= new List<VolSurfaceSymbolRelationship>();
|
||||
settings.core_settings.implied_vol_marketdata_relationships ??= new List<VolSurfaceSymbolRelationship>();
|
||||
_dispose = new DisposableCombo(
|
||||
bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(on_exp_params_input)) +
|
||||
new Action(() => Disposable.dispose(driver_grids));
|
||||
_dispose = Disposable.Create(
|
||||
driver_grids.Subscribe((s, e) =>
|
||||
selected_driver_grid ??= driver_grids.FirstOrDefault()),
|
||||
bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(on_exp_params_input),
|
||||
Disposable.Create(() => driver_grids.DisposeAll(true)));
|
||||
|
||||
void on_exp_params_input(AnalyticsExpirationParametersMap data) {
|
||||
var driver_map = data.get_option_driver_map();
|
||||
@@ -586,6 +613,10 @@ namespace mbts.spark {
|
||||
|
||||
public IReadOnlyList<VolSurfaceEnums.VolSurfacePricingModel> pricing_models => EnumHelper.get_values<VolSurfaceEnums.VolSurfacePricingModel>();
|
||||
public ObservableCollection<VSSymbolGridVM> driver_grids { get; private set; }
|
||||
public VSSymbolGridVM selected_driver_grid {
|
||||
get => _selected_driver_grid.Value;
|
||||
set => _selected_driver_grid.set(value);
|
||||
}
|
||||
}
|
||||
|
||||
public class RotationVM : ViewModelBase, IEquatable<RotationVM> {
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
|
||||
using Spark.Core.Reflection;
|
||||
using Spark.ViewModel.Commands;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
class VolSurfaceMacroActionsVM : ViewModelBase {
|
||||
readonly VolSurfaceDisplayModel _model;
|
||||
@@ -76,8 +77,8 @@
|
||||
public IRaiseCanExecuteChangedCommand vol_shift { get; }
|
||||
|
||||
IEnumerable<IRaiseCanExecuteChangedCommand> _commands =>
|
||||
ObjectSnapshot.property_delegates_of_type<VolSurfaceMacroActionsVM, IRaiseCanExecuteChangedCommand>()
|
||||
.Select(g => g(this));
|
||||
ReflectionHelper.property_getters<VolSurfaceMacroActionsVM, IRaiseCanExecuteChangedCommand>()
|
||||
.Select(pg => pg.get(this));
|
||||
|
||||
public void selection_changed(IEnumerable<VolSurfaceDisplayGridExpiration> selected) {
|
||||
_selected_exps = selected.ToList();
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.utility;
|
||||
|
||||
using Spark.ViewModel.Commands;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#nullable enable
|
||||
namespace mbts.spark {
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.collections;
|
||||
|
||||
@@ -8,48 +8,107 @@ namespace mbts.spark {
|
||||
using mbts.spark.VolSurface;
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.settings;
|
||||
using mbts.ui.shell;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.ViewModel.Commands;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
class VolSurfaceVM : ViewModelBase, IDisposable {
|
||||
class VolSurfaceVM : DisposableViewModelBase {
|
||||
readonly int _vs_id;
|
||||
readonly IBus _bus;
|
||||
readonly string _request_id = Guid.NewGuid().ToString();
|
||||
VolSurfaceDisplayModel _model;
|
||||
VolSurfaceMacroGridSettings _grid_settings;
|
||||
readonly VolSurfaceDisplayModel _model;
|
||||
readonly IRaiseCanExecuteChangedCommand _revert_cmd;
|
||||
readonly IRaiseCanExecuteChangedCommand _commit_cmd;
|
||||
readonly IDialogCommand _main_settings_cmd;
|
||||
readonly IDialogCommand _advanced_settings_cmd;
|
||||
readonly IDialogCommand _grid_settings_cmd;
|
||||
|
||||
public VolSurfaceVM(VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
|
||||
Log.notnull(startup_data);
|
||||
string? _selected_state = string.Empty;
|
||||
VolSurfaceMacroGridSettings _grid_settings;
|
||||
bool _ignore_implied_vol_settings;
|
||||
|
||||
public VolSurfaceVM(
|
||||
VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
|
||||
_model = model;
|
||||
var demux = new VolSurfaceEventDemux(model);
|
||||
_vs_id = id;
|
||||
_bus = bus;
|
||||
macro_actions = new VolSurfaceMacroActionsVM(_model);
|
||||
globals = new VolSurfaceGlobalParameterVM(_model);
|
||||
|
||||
// grid
|
||||
_grid_settings = startup_data.macro_grid_settings ?? new VolSurfaceMacroGridSettings();
|
||||
var hidden_exps_set = startup_data.hidden_exps.empty_if_null().ToHashSet();
|
||||
grid = new VolSurfaceGridVM(
|
||||
this, _model, _grid_settings.hidden_cols(), hidden_exps_set);
|
||||
grid.on_selection_changed += _on_grid_selection_changed;
|
||||
_model.publish_grid_settings(_grid_settings);
|
||||
|
||||
// graphs
|
||||
var demux = new VolSurfaceEventDemux(model);
|
||||
vol_curve_vm = new VolSurfaceGraphVM(
|
||||
_model, demux, startup_data, (show_ivol, exp) => _model.publish_new_grid_selection(_request_id, exp, show_ivol));
|
||||
_model, demux, startup_data, (show_ivol, exp) =>
|
||||
_model.publish_new_grid_selection(_request_id, exp, show_ivol));
|
||||
vol_terms_vm = new VolTermsGraphVM(_model, demux);
|
||||
revert_command = new DelegateCommand(o => _model.revert(), o => _model.is_dirty);
|
||||
commit_command = new DelegateCommand(o => _model.commit(), o => _model.is_dirty);
|
||||
load_previous_command = new DelegateCommand(_ => { var cur = selected_previous_state; selected_previous_state = null; _model.load_previous_state(cur); }, _ => !string.IsNullOrEmpty(selected_previous_state));
|
||||
main_settings_command = new DialogCommand(() => {
|
||||
|
||||
// command
|
||||
populate_empty_exps_cmd = new Command(() => { _model.populate_empty_expirations(); });
|
||||
_revert_cmd = new Command(o => _model.revert(), o => _model.is_dirty);
|
||||
_commit_cmd = new Command(o => _model.commit(), o => _model.is_dirty);
|
||||
load_previous_cmd = new Command(
|
||||
load_previous, () => !selected_previous_state.is_null_or_empty());
|
||||
_main_settings_cmd = new DialogCommand(mk_main_settings_win);
|
||||
_advanced_settings_cmd = new DialogCommand(mk_advanced_settings_win);
|
||||
_grid_settings_cmd = new DialogCommand(mk_grid_settings_win);
|
||||
|
||||
_model.on_dirty_change += () => {
|
||||
RaisePropertyChanged(nameof(is_dirty));
|
||||
_revert_cmd.RaiseCanExecuteChanged();
|
||||
_commit_cmd.RaiseCanExecuteChanged();
|
||||
};
|
||||
demux.on_candidate_grid_change += () =>
|
||||
previous_states.sync_with(_model.get_previous_states());
|
||||
demux.on_schema_change += () => {
|
||||
var existing_cols = _grid_settings.column_settings.ToDictionary(c => c.id);
|
||||
_grid_settings.set_columns(
|
||||
model.get_active_grid()
|
||||
.get_ordered_columns()
|
||||
.Select(col => existing_cols.GetValueOrDefault(col.unique_col_name) ??
|
||||
VolSurfaceColumnSettings.from_column_model(col)));
|
||||
};
|
||||
|
||||
_dispose = Disposable.Create(
|
||||
vol_curve_vm,
|
||||
vol_terms_vm,
|
||||
globals,
|
||||
Disposable.Create(() => grid?.Dispose()),
|
||||
_main_settings_cmd,
|
||||
_advanced_settings_cmd,
|
||||
_grid_settings_cmd,
|
||||
_model);
|
||||
Window? mk_main_settings_win() {
|
||||
var settings = _model.get_active_settings();
|
||||
if (settings == null) {
|
||||
if (settings is null) {
|
||||
return null;
|
||||
}
|
||||
return new VolSurfaceSettingsEditor { DataContext = new VolSurfaceSettingsEditorVM(_bus, settings, _model.set_candidate_settings) };
|
||||
});
|
||||
advanced_settings_command = new DialogCommand(() => {
|
||||
return new VolSurfaceSettingsEditor {
|
||||
DataContext = new VolSurfaceSettingsEditorVM(
|
||||
_bus, settings, _model.set_candidate_settings) {
|
||||
can_edit_name = false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Window? mk_advanced_settings_win() {
|
||||
var settings = _model.get_active_settings();
|
||||
if (settings == null) {
|
||||
return null;
|
||||
@@ -69,76 +128,72 @@ namespace mbts.spark {
|
||||
// )
|
||||
// };
|
||||
return null;
|
||||
});
|
||||
grid_settings_command = new DialogCommand(() => {
|
||||
}
|
||||
|
||||
Window? mk_grid_settings_win() {
|
||||
var settings = _model.get_active_settings();
|
||||
if (settings == null) {
|
||||
if (settings is null) {
|
||||
return null;
|
||||
}
|
||||
var vm = new VolSurfaceGridSettingsEditorVM(settings.core_settings.vol_surface_name, _grid_settings.Clone());
|
||||
var vm = new VolSurfaceGridSettingsEditorVM(
|
||||
settings.core_settings.vol_surface_name, _grid_settings.Clone());
|
||||
vm.request_commit += on_grid_settings;
|
||||
return new VolSurfaceGridSettingsEditor {
|
||||
DataContext = vm
|
||||
};
|
||||
});
|
||||
_model.on_dirty_change += raise_dirty_changed;
|
||||
macro_actions = new VolSurfaceMacroActionsVM(_model);
|
||||
globals = new VolSurfaceGlobalParameterVM(_model);
|
||||
demux.on_candidate_grid_change += () => previous_states.sync_with(_model.get_previous_states());
|
||||
demux.on_schema_change += () => {
|
||||
// _grid_settings.clear_columns();
|
||||
var existing_cols = _grid_settings.column_settings.ToDictionary(c => c.id);
|
||||
_grid_settings.set_columns(
|
||||
model.get_active_grid()
|
||||
.get_ordered_columns()
|
||||
.Select(col => {
|
||||
if (!existing_cols.TryGetValue(col.unique_col_name, out var rv)) {
|
||||
rv = VolSurfaceColumnSettings.from_column_model(col);
|
||||
}
|
||||
return rv;
|
||||
}));
|
||||
};
|
||||
grid = new VolSurfaceGridVM(this, _model, _grid_settings.hidden_cols(), new HashSet<VolSurfaceExpiration>(startup_data.hidden_exps ?? Enumerable.Empty<VolSurfaceExpiration>()));
|
||||
grid.on_selection_changed += _on_grid_selection_changed;
|
||||
|
||||
void on_grid_settings(VolSurfaceMacroGridSettings new_settings) {
|
||||
using var _ = grid.defer_invalidate_rows();
|
||||
_grid_settings = new_settings;
|
||||
grid.load_from(_grid_settings);
|
||||
grid.invalidate_rows();
|
||||
_model.publish_grid_settings(_grid_settings);
|
||||
void on_grid_settings(VolSurfaceMacroGridSettings new_settings) {
|
||||
using var _ = grid.defer_invalidate_rows();
|
||||
_grid_settings = new_settings;
|
||||
grid.load_from(_grid_settings);
|
||||
grid.invalidate_rows();
|
||||
_model.publish_grid_settings(_grid_settings);
|
||||
}
|
||||
}
|
||||
|
||||
void load_previous() {
|
||||
var cur = selected_previous_state;
|
||||
selected_previous_state = null;
|
||||
_model.load_previous_state(cur);
|
||||
}
|
||||
}
|
||||
|
||||
public VolSurfaceGridVM grid { get; private set; }
|
||||
public VolSurfaceGraphVM vol_curve_vm { get; private set; }
|
||||
public VolTermsGraphVM vol_terms_vm { get; private set; }
|
||||
public VolSurfaceMacroActionsVM macro_actions { get; private set; }
|
||||
public VolSurfaceGlobalParameterVM globals { get; private set; }
|
||||
public VolSurfaceGridVM grid { get; }
|
||||
public VolSurfaceGraphVM vol_curve_vm { get; }
|
||||
public VolTermsGraphVM vol_terms_vm { get; }
|
||||
public VolSurfaceMacroActionsVM macro_actions { get; }
|
||||
public VolSurfaceGlobalParameterVM globals { get; }
|
||||
|
||||
private bool _ignore_implied_vol_settings;
|
||||
public bool ignore_implied_vol_settings { get { return _ignore_implied_vol_settings; } set { _model.publish_ignore_implied_vol_settings(_request_id, _ignore_implied_vol_settings = value); } }
|
||||
|
||||
public bool is_dirty { get { return _model.is_dirty; } }
|
||||
public IRaiseCanExecuteChangedCommand revert_command { get; private set; }
|
||||
public IRaiseCanExecuteChangedCommand commit_command { get; private set; }
|
||||
public IDialogCommand main_settings_command { get; private set; }
|
||||
public IDialogCommand advanced_settings_command { get; private set; }
|
||||
public IDialogCommand grid_settings_command { get; private set; }
|
||||
public ICommand details_command => new DelegateCommand(_ => _show_details());
|
||||
|
||||
public ICommand load_previous_command { get; private set; }
|
||||
public ObservableCollection<string> previous_states { get; } = new();
|
||||
private string _selected_state = string.Empty;
|
||||
public string selected_previous_state {
|
||||
get { return _selected_state; }
|
||||
public bool ignore_implied_vol_settings {
|
||||
get => _ignore_implied_vol_settings;
|
||||
set {
|
||||
_selected_state = value;
|
||||
load_previous_command.TryRaiseCanExecuteChanged();
|
||||
RaisePropertyChanged();
|
||||
if (Set(ref _ignore_implied_vol_settings, value)) {
|
||||
_model.publish_ignore_implied_vol_settings(_request_id, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<string> previous_states { get; } = new();
|
||||
public string? selected_previous_state {
|
||||
get => _selected_state;
|
||||
set {
|
||||
if (Set(ref _selected_state, value)) {
|
||||
load_previous_cmd.TryRaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool is_dirty => _model.is_dirty;
|
||||
|
||||
public ICommand revert_cmd => _revert_cmd;
|
||||
public ICommand commit_cmd => _commit_cmd;
|
||||
public ICommand populate_empty_exps_cmd { get; }
|
||||
public ICommand main_settings_cmd => _main_settings_cmd;
|
||||
public ICommand advanced_settings_cmd => _advanced_settings_cmd;
|
||||
public ICommand grid_settings_cmd => _grid_settings_cmd;
|
||||
public ICommand details_command => new Command(_show_details);
|
||||
public ICommand load_previous_cmd { get; }
|
||||
|
||||
public VolSurfaceWindowSettings get_startup_data() {
|
||||
var rv = new VolSurfaceWindowSettings {
|
||||
id = _vs_id,
|
||||
@@ -152,39 +207,20 @@ namespace mbts.spark {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
vol_curve_vm.Dispose();
|
||||
vol_terms_vm.Dispose();
|
||||
globals.Dispose();
|
||||
if (grid != null) grid.Dispose();
|
||||
main_settings_command.Dispose();
|
||||
advanced_settings_command.Dispose();
|
||||
grid_settings_command.Dispose();
|
||||
Disposable.dispose(ref _model);
|
||||
}
|
||||
|
||||
void raise_dirty_changed() {
|
||||
RaisePropertyChanged("is_dirty");
|
||||
revert_command.RaiseCanExecuteChanged();
|
||||
commit_command.RaiseCanExecuteChanged();
|
||||
}
|
||||
|
||||
void _on_grid_selection_changed(IEnumerable<VolSurfaceDisplayGridExpiration> selection) {
|
||||
var selected = selection.FirstOrDefault();
|
||||
if (selected != null) {
|
||||
if (selection.TryGetFirst(out var selected)) {
|
||||
vol_curve_vm.set_visible_expiration(selected);
|
||||
_model.publish_new_grid_selection(_request_id, selected, vol_curve_vm.show_implied_vol);
|
||||
}
|
||||
macro_actions.selection_changed(selection);
|
||||
}
|
||||
|
||||
async Task<VolSurfaceSettings> _get_volsurface_settings() =>
|
||||
(await _bus.subscribe(SparkTags.VolSurfaceCommittedOutputTag(_vs_id)).FirstOrDefaultAsync())
|
||||
?.volsurface_input
|
||||
?.surface_settings;
|
||||
|
||||
void _show_details() =>
|
||||
_model.show_details();
|
||||
|
||||
async Task<VolSurfaceSettings?> _get_volsurface_settings() =>
|
||||
(await _bus.subscribe(SparkTags.VolSurfaceCommittedOutputTag(_vs_id)).FirstOrDefaultAsync())
|
||||
?.volsurface_input
|
||||
?.surface_settings;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,22 @@
|
||||
using bts.api;
|
||||
using bts.utils;
|
||||
namespace mbts.spark {
|
||||
using bts.api;
|
||||
using bts.collections;
|
||||
|
||||
using mbts.analytics;
|
||||
using mbts.collections;
|
||||
using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
using mbts.analytics;
|
||||
using mbts.collections;
|
||||
using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using Spark.Core;
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace mbts.spark {
|
||||
class VolTermsGraphVM : DisposableViewModelBase {
|
||||
readonly VolSurfaceDisplayModel _model;
|
||||
readonly DateTimeAxisVM _exp_terms_x_axis;
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
using mbts.analytics;
|
||||
using mbts.ui.controls;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -124,6 +127,20 @@
|
||||
_log_bad_transition(_state, "set candidate grid");
|
||||
}
|
||||
|
||||
public void populate_empty_expirations() {
|
||||
bts.Log.Ui.info(String.Format("VolSurfaceDisplayModel.populate_expirations called with state: {0}",
|
||||
_state.ToString()));
|
||||
if (_state == DisplayModelState.Idle || _state == DisplayModelState.ResponseReady) {
|
||||
DisplayModelData curr_data = _get_current_data();
|
||||
VolSurfaceInput vs_inp =
|
||||
VolSurfaceDataFunctions.populate_empty_expirations(curr_data.vs_output.volsurface_input);
|
||||
_change_state(DisplayModelState.WaitingForCalcResponse);
|
||||
_bus.post(SparkTags.VolSurfaceCalculationRequestTag(_vs_id),
|
||||
new VolSurfaceCalculationRequest(vs_inp, _request_version_no++));
|
||||
} else
|
||||
_log_bad_transition(_state, "populate_expirations");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Globals
|
||||
@@ -143,6 +160,7 @@
|
||||
return (_committed_data != null && _committed_data.vs_output != null) ? _committed_data.vs_output.volsurface_input.surface_parameters.vol_time : DateTime.MinValue;
|
||||
}
|
||||
public void set_candidate_vol_time(DateTime vol_time) {
|
||||
bts.Log.Ui.info($"VolSurfaceDisplayModel.set_candidate_vol_time vs_id: {_vs_id} state: {_state.ToString()} vol_time: {vol_time}");
|
||||
if (_state == DisplayModelState.Idle || _state == DisplayModelState.ResponseReady) {
|
||||
DisplayModelData curr_data = _get_current_data();
|
||||
if (curr_data != null) {
|
||||
@@ -296,7 +314,7 @@
|
||||
bool succ = false;
|
||||
VolSurfaceInputSnapshot vs_sn = _input_snapshot_list.ToList().Find(v => v.save_marker == state_name);
|
||||
if (vs_sn != null) {
|
||||
VolSurfaceInput vs_inp = VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(vs_sn.data);
|
||||
var vs_inp = ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs_sn.data);
|
||||
if (vs_inp != null) {
|
||||
_change_state(DisplayModelState.WaitingForCalcResponse);
|
||||
_bus.post(SparkTags.VolSurfaceCalculationRequestTag(_vs_id),
|
||||
@@ -319,7 +337,7 @@
|
||||
public byte[] get_current_state() {
|
||||
DisplayModelData curr_data = _get_current_data();
|
||||
if (curr_data != null && curr_data.vs_output != null && curr_data.vs_output.volsurface_input != null)
|
||||
return VolSurfaceUtilityFunctions.serialize_proto(curr_data.vs_output.volsurface_input);
|
||||
return ProtobufSerializationHelper.serialize(curr_data.vs_output.volsurface_input);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
@@ -327,7 +345,7 @@
|
||||
/// Sets the state that is passed in bytes form. Returns
|
||||
/// true is state is set successfully
|
||||
public bool set_state(byte[] file_data) {
|
||||
VolSurfaceInput vs_input = VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(file_data);
|
||||
var vs_input = ProtobufSerializationHelper.deserialize<VolSurfaceInput>(file_data);
|
||||
if (vs_input != null) {
|
||||
if (_state == DisplayModelState.Idle || _state == DisplayModelState.ResponseReady) {
|
||||
_change_state(DisplayModelState.WaitingForCalcResponse);
|
||||
@@ -566,9 +584,7 @@
|
||||
private void _change_state(DisplayModelState new_state) {
|
||||
bool dirty_before = _translate_to_dirty(_state),
|
||||
dirty_after = _translate_to_dirty(new_state);
|
||||
// mbts.Logger.log(bts.log.Level.Info, bts.log.Subsystem.ui,
|
||||
// String.Format("State change {0}->{1}", _state.ToString(), new_state.ToString()));
|
||||
bts.Log.Ui.info(String.Format("State change {0}->{1}", _state.ToString(), new_state.ToString()));
|
||||
bts.Log.Ui.info($"VolSurfaceDisplayModel._change_state vs_id: {_vs_id} {_state.ToString()}->{new_state.ToString()}");
|
||||
_state = new_state;
|
||||
if (dirty_before != dirty_after && on_dirty_change != null) {
|
||||
_bus.post(SparkTags.VolSurfaceDirtyStateTag(_vs_id), dirty_after);
|
||||
@@ -611,9 +627,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
private static void _log_bad_transition(DisplayModelState state, string action) {
|
||||
//mbts.Logger.log(bts.log.Level.Error, bts.log.Subsystem.ui, String.Format("{0}:{1}", state, action));
|
||||
bts.Log.Ui.error(String.Format("{0}:{1}", state, action));
|
||||
private void _log_bad_transition(DisplayModelState state, string action) {
|
||||
bts.Log.Ui.error($"VoLSurfaceDisplayModel bad_transaction vs_id: {_vs_id} {state}:{action}");
|
||||
}
|
||||
|
||||
private static bool _translate_to_dirty(DisplayModelState state) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace mbts.spark {
|
||||
namespace mbts.spark {
|
||||
using bts.api;
|
||||
using bts.api.analytics;
|
||||
using bts.utils;
|
||||
@@ -34,6 +34,9 @@
|
||||
public static HashSet<string> hidden_cols(this VolSurfaceMacroGridSettings gs) =>
|
||||
new(gs.column_settings.Where(cc => !cc.is_visible).Select(cc => cc.id));
|
||||
|
||||
public static bool is_editable(this VolSurfaceColumnType vs_col_type) =>
|
||||
vs_col_type is VolSurfaceColumnType.ReadWriteTick;
|
||||
|
||||
public static analytics.VolSurfaceExpiration ToVSExp(this VolSurfaceDisplayGridExpiration vsdge) =>
|
||||
new() { expiration = vsdge.expiration, symbol = vsdge.symbol };
|
||||
|
||||
@@ -80,10 +83,10 @@
|
||||
_ => false,
|
||||
};
|
||||
|
||||
public static IEnumerable<VolSurfaceExpiration> select_exp(this IEnumerable<VolSurfaceRowContext> rows) =>
|
||||
public static IEnumerable<VolSurfaceExpiration> select_exp(this IEnumerable<VolSurfaceRowVM> rows) =>
|
||||
rows.Select(r => r.expiration.ToVSExp());
|
||||
|
||||
public static IEnumerable<VolSurfaceDisplayGridExpiration> select_display_exp(this IEnumerable<VolSurfaceRowContext> rows) =>
|
||||
public static IEnumerable<VolSurfaceDisplayGridExpiration> select_display_exp(this IEnumerable<VolSurfaceRowVM> rows) =>
|
||||
rows.Select(r => r.expiration);
|
||||
|
||||
public static IEnumerable<VolSurfaceDisplayGridExpiration> where_master(this IEnumerable<VolSurfaceDisplayGridExpiration> rows) =>
|
||||
@@ -113,6 +116,106 @@
|
||||
public static IEnumerable<(double x, double y)> real_all_points(this VolCurveDisplayGraph graph) =>
|
||||
_select_real_points(graph.all_points);
|
||||
|
||||
public static bool is_delta_greek(this VolSurfaceGreeks g) =>
|
||||
g switch {
|
||||
VolSurfaceGreeks.Delta or
|
||||
VolSurfaceGreeks.Bsmdelta or
|
||||
VolSurfaceGreeks.FlatVolDelta or
|
||||
VolSurfaceGreeks.ExpirationDelta or
|
||||
VolSurfaceGreeks.Charm or
|
||||
VolSurfaceGreeks.Vanna => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
public static bool is_gamma_greek(this VolSurfaceGreeks g) =>
|
||||
g switch {
|
||||
VolSurfaceGreeks.Gamma or
|
||||
VolSurfaceGreeks.Bsmgamma => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
public static bool is_oev_col(this VolSurfaceGreeks g) =>
|
||||
g switch {
|
||||
VolSurfaceGreeks.Oev or
|
||||
VolSurfaceGreeks.Bsmoev => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
public static VolSurfaceExpiration to_vs_exp(this SecurityExpiration sec_exp) =>
|
||||
new() { security_type = sec_exp.security_type, symbol = sec_exp.symbol, expiration = sec_exp.expiration };
|
||||
|
||||
public static DriverCalculationType to_driver_calc_type(
|
||||
this ExpirationDriver.ModeOneofCase driver_mode) =>
|
||||
driver_mode switch {
|
||||
ExpirationDriver.ModeOneofCase.Security => DriverCalculationType.Direct,
|
||||
ExpirationDriver.ModeOneofCase.TimeWeightedInterpolated => DriverCalculationType.TimeWeightedInterp,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
public static SecurityExpiration to_sec_exp(
|
||||
this bts.api.domain.SecurityExpiration api_sec_exp) =>
|
||||
to_sec_exp(new bts.api.domain.SecurityExpirationImmutable(api_sec_exp));
|
||||
|
||||
public static SecurityExpiration to_sec_exp(
|
||||
this bts.api.domain.SecurityExpirationImmutable api_sec_exp) =>
|
||||
new(
|
||||
api_sec_exp.Exchange.to_venue(),
|
||||
api_sec_exp.SecurityType.contract_case(),
|
||||
api_sec_exp.Symbol,
|
||||
api_sec_exp.Expiration.date_time());
|
||||
|
||||
public static SecurityExpiration to_sec_exp(this Security sec) =>
|
||||
to_sec_exp(new SecurityImmutable(sec));
|
||||
|
||||
public static SecurityExpiration to_sec_exp(this SecurityImmutable sec) {
|
||||
var exp_date = sec.security_expiration() ?? throw new InvalidOperationException();
|
||||
return new(sec.Exchange, sec.ContractCase, sec.Symbol, exp_date, sec.Id);
|
||||
}
|
||||
|
||||
public static SecurityTuple security_tuple(this Security sec) {
|
||||
return security_tuple(new SecurityImmutable(sec));
|
||||
}
|
||||
|
||||
public static SecurityTuple security_tuple(this SecurityImmutable sec) {
|
||||
bts.api.SecurityTuple rv = new SecurityTuple();
|
||||
rv.Symbol = sec.Symbol;
|
||||
rv.Type = sec.security_type();
|
||||
rv.Venue = sec.Exchange;
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static ExpirationDriver to_exp_driver(this SecurityExpiration sec_exp) =>
|
||||
new() {
|
||||
Security = new() {
|
||||
Symbol = sec_exp.symbol,
|
||||
Expiration = new() {
|
||||
ExpirationDay = (uint)sec_exp.expiration.Day,
|
||||
ExpirationMonth = (uint)sec_exp.expiration.Month,
|
||||
ExpirationYear = (uint)sec_exp.expiration.Year,
|
||||
},
|
||||
Exchange = sec_exp.exchange.to_api_venue(),
|
||||
}
|
||||
};
|
||||
|
||||
public static ExpirationDriverImmutable to_exp_driveri(this SecurityExpiration sec_exp) =>
|
||||
new(to_exp_driver(sec_exp));
|
||||
|
||||
public static bts.api.domain.SecurityExpiration to_api_sec_exp(this SecurityExpiration sec_exp) =>
|
||||
new() {
|
||||
Exchange = sec_exp.exchange.to_api_venue(),
|
||||
SecurityType = sec_exp.security_type,
|
||||
Symbol = sec_exp.symbol,
|
||||
Expiration = new() {
|
||||
ExpirationDay = (uint)sec_exp.expiration.Day,
|
||||
ExpirationMonth = (uint)sec_exp.expiration.Month,
|
||||
ExpirationYear = (uint)sec_exp.expiration.Year
|
||||
}
|
||||
};
|
||||
|
||||
public static bts.api.domain.SecurityExpirationImmutable to_api_sec_expi(
|
||||
this SecurityExpiration sec_exp) =>
|
||||
new(to_api_sec_exp(sec_exp));
|
||||
|
||||
static IEnumerable<(double x, double y)> _select_real_points(IEnumerable<Tuple<double, double>> points) =>
|
||||
points.Where(pt => pt.Item1.is_real() && pt.Item2.is_real()).Select(t => (t.Item1, t.Item2));
|
||||
}
|
||||
|
||||
@@ -24,13 +24,14 @@ Value: OptionDriverPriceMap which is a wrapper around
|
||||
IDictionary<SecurityExpiration, Tuple<Security, VolSurfaceBBOUnit>>
|
||||
|
||||
----------------------------------------------------------------
|
||||
SingleVolSurfaceInterpGreeksPublisher listens to all inputs and publishes
|
||||
exp vs InterpGreeks
|
||||
SingleVolSurfaceInterpGreeksPublisher (for one vs) listens to all inputs and publishes
|
||||
IDictionary<VolSurfaceExpiration, IEnumerable<Theos>>
|
||||
|
||||
VolSurfaceInterpGreeksMultiplexer listens to all vol surfaces, resolves symbols and
|
||||
publishes symbol vs InterpGreeks
|
||||
VolSurfaceInterpGreeksMultiplexer (for multiple option symbols) listens to all vol
|
||||
surfaces, resolves symbols and for each option_symbol publishes
|
||||
OptionTheoInterpolationData*
|
||||
|
||||
SymbolAggregationPublisher is a thin class that combines individual symbol data and
|
||||
SymbolAggregationPublisher is a thin generic class that combines individual symbol data and
|
||||
publishes symbol vs data map
|
||||
|
||||
LiveTheoPublisher:
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.admin;
|
||||
using bts.api.core;
|
||||
using bts.collections;
|
||||
using bts.utils;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Composition;
|
||||
@@ -18,10 +22,10 @@ namespace mbts.spark {
|
||||
IReadOnlyDictionary<uint, string> _account_map = DictionaryHelper.empty<uint, string>();
|
||||
|
||||
[ImportingConstructor]
|
||||
public AdminModel(AdminService service, Lazy<UserTuple> user)
|
||||
: this(service, user.Value) { }
|
||||
public AdminModel(IBus bus, AdminService service, Lazy<UserTuple> user)
|
||||
: this(bus, service, user.Value) { }
|
||||
|
||||
AdminModel(AdminService service, UserTuple user) {
|
||||
AdminModel(IBus bus, AdminService service, UserTuple user) {
|
||||
this.user = user;
|
||||
// accounts
|
||||
on_accounts = service.subscribei_admin_data()
|
||||
@@ -39,7 +43,7 @@ namespace mbts.spark {
|
||||
on_users = Observable.Return(DictionaryHelper.wrap_value(user.id, user.name));
|
||||
all_user_tuples = user.permissions == UserTuple.Permissions.Admin ?
|
||||
service.subscribei_admin_data()
|
||||
.Select(u => u.all.TryFirst())
|
||||
.Select(u => u.all.FirstOrNull())
|
||||
.Where(ad => ad.HasValue)
|
||||
.Select(ad => ad.Value.Users
|
||||
.Where(u => user.can_access_user_data(u.Id))
|
||||
@@ -48,7 +52,14 @@ namespace mbts.spark {
|
||||
.Table(UserTuple.key_fn)
|
||||
.Cache() :
|
||||
Observable.Return(TableUpdate<UserTuple, uint>.mk_empty(UserTuple.key_fn).with_added(new[] { user }));
|
||||
_dispose = on_accounts.Subscribe(map => _account_map = map);
|
||||
_dispose = Disposable.Create(
|
||||
all_user_tuples.Subscribe(t => bus.post(SparkTags.Users, t.state)),
|
||||
on_accounts.Subscribe(map => {
|
||||
_account_map = map;
|
||||
var account_tuple_map = MappedDictionary.create(map, (id, name) => new AccountTuple(id, name));
|
||||
bus.post(SparkTags.AccountsTag, account_tuple_map);
|
||||
}));
|
||||
bus.post(SparkTags.CurrentUser, user);
|
||||
}
|
||||
|
||||
public IObservable<IReadOnlyDictionary<uint, string>> on_users { get; }
|
||||
@@ -70,7 +81,7 @@ namespace mbts.spark {
|
||||
}));
|
||||
|
||||
public AccountTuple? get_default_account() =>
|
||||
_account_map.Select(kv => new AccountTuple(kv.Key, kv.Value)).TryFirst();
|
||||
_account_map.Select(kv => new AccountTuple(kv.Key, kv.Value)).FirstOrNull();
|
||||
|
||||
public void Dispose() =>
|
||||
Disposable.dispose(ref _dispose);
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace mbts.spark {
|
||||
this AlgoTypeSetImmutable algo_set,
|
||||
DynamicOrderHelper dynamic_helper,
|
||||
Func<CustomOrderDefinitionImmutable, CustomOrderDefinitionImmutable> fit_to_type = null,
|
||||
uint display_qty_divisor = 1) =>
|
||||
double display_qty_divisor = 1) =>
|
||||
//
|
||||
algo_set.factory_types
|
||||
.Select(algo_type => {
|
||||
@@ -109,7 +109,7 @@ namespace mbts.spark {
|
||||
SecurityCriteriaClause clause,
|
||||
DynamicOrderHelper dynamic_helper,
|
||||
Func<CustomOrderDefinitionImmutable, CustomOrderDefinitionImmutable> fit_to_type = null,
|
||||
uint display_qty_divisor = 1) {
|
||||
double display_qty_divisor = 1) {
|
||||
//
|
||||
ImmutableDictionary<AlgoKey, AlgoData> rv = null;
|
||||
foreach (var set in security_algo_sets) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using bts.api;
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.core;
|
||||
using bts.api.orderman;
|
||||
using bts.utils;
|
||||
@@ -50,9 +51,7 @@ namespace mbts.spark {
|
||||
/// <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();
|
||||
_studio_algos_source = studio_model.definitions.Cache();
|
||||
}
|
||||
|
||||
public AlgoTypeSetImmutable get_permitted_algos(SecurityImmutable security) =>
|
||||
@@ -67,10 +66,11 @@ namespace mbts.spark {
|
||||
|
||||
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));
|
||||
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
|
||||
.AppendTable(_security_algo_types
|
||||
.Select(s => s.algo_type_set)
|
||||
.Aggregate(AlgoTypeSetImmutable.empty, (a, b) => a.union_with(b))
|
||||
.define_algos(_dynamic_helper));
|
||||
|
||||
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityCriteriaClause security_clause) {
|
||||
var system_algos = _security_algo_types.match_algos(
|
||||
@@ -78,11 +78,13 @@ namespace mbts.spark {
|
||||
_dynamic_helper,
|
||||
def => _fit_to_type(def, security_clause, _security_algo_types));
|
||||
|
||||
return _studio_algos_source.Select(
|
||||
a => (algo: a, fitted_def: _fit_to_type(a.value, security_clause, _security_algo_types)),
|
||||
tup => tup.algo.key)
|
||||
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), a => a.key)
|
||||
.AppendTable(system_algos.Values);
|
||||
return _studio_algos_source
|
||||
.Select(
|
||||
a => (algo: a, fitted_def: _fit_to_type(a.value, security_clause, _security_algo_types)),
|
||||
tup => tup.algo.key)
|
||||
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), a => a.key)
|
||||
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
|
||||
.AppendTable(system_algos.Values);
|
||||
}
|
||||
|
||||
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityImmutable security) {
|
||||
@@ -96,14 +98,18 @@ namespace mbts.spark {
|
||||
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);
|
||||
var filtered_studio_algos = _studio_algos_source
|
||||
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
|
||||
.Select(
|
||||
a => (algo: a, fitted_def: _fit_to_type(a.value, security, _security_algo_types)),
|
||||
tup => tup.algo.key)
|
||||
// filter out algos that use an unsupported root, because this would have the effect of duplicating the default algo
|
||||
// (e.g., GlbxIceberg orders would be converted to Limit/Spreader orders for non-Glbx securities).
|
||||
.Filter(tup => tup.fitted_def.actual().CustomCase == tup.algo.value.actual().CustomCase, tup => tup.algo.key)
|
||||
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), AlgoData.key_fn);
|
||||
return filtered_studio_algos
|
||||
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
|
||||
.AppendTable(system_algos.Values);
|
||||
}
|
||||
|
||||
protected virtual void assign_fallback_algo(CustomOrderDefinition mdef, SecurityCriteriaClause security_clause) {
|
||||
|
||||
@@ -10,7 +10,8 @@ namespace mbts.analytics {
|
||||
double gamma = double.NaN,
|
||||
double vega = double.NaN,
|
||||
double theta = double.NaN,
|
||||
double rho = double.NaN) {
|
||||
double rho = double.NaN,
|
||||
double normalized_theo = double.NaN) {
|
||||
this.vol = vol;
|
||||
this.driver = driver;
|
||||
this.theo = theo;
|
||||
@@ -19,6 +20,7 @@ namespace mbts.analytics {
|
||||
this.vega = vega;
|
||||
this.theta = theta;
|
||||
this.rho = rho;
|
||||
this.normalized_theo = normalized_theo;
|
||||
}
|
||||
|
||||
public static GreeksTuple empty => new();
|
||||
@@ -31,6 +33,7 @@ namespace mbts.analytics {
|
||||
public double vega { get; }
|
||||
public double theta { get; }
|
||||
public double rho { get; }
|
||||
public double normalized_theo { get; }
|
||||
|
||||
public bool Equals(GreeksTuple other) =>
|
||||
vol.Equals(other.vol) &&
|
||||
@@ -65,7 +68,8 @@ namespace mbts.analytics {
|
||||
double? gamma = null,
|
||||
double? vega = null,
|
||||
double? theta = null,
|
||||
double? rho = null) =>
|
||||
double? rho = null,
|
||||
double? normalized_theo = null) =>
|
||||
new(
|
||||
vol ?? greeks_tuple.vol,
|
||||
driver ?? greeks_tuple.driver,
|
||||
@@ -74,12 +78,7 @@ namespace mbts.analytics {
|
||||
gamma ?? greeks_tuple.gamma,
|
||||
vega ?? greeks_tuple.vega,
|
||||
theta ?? greeks_tuple.theta,
|
||||
rho ?? greeks_tuple.rho);
|
||||
|
||||
public static double normalized_theo(this in GreeksTuple greeks_tuple) =>
|
||||
greeks_tuple.theo / greeks_tuple.driver;
|
||||
|
||||
public static double normalized_delta(this in GreeksTuple greeks_tuple) =>
|
||||
greeks_tuple.delta / greeks_tuple.driver;
|
||||
rho ?? greeks_tuple.rho,
|
||||
normalized_theo ?? greeks_tuple.normalized_theo);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace mbts.analytics {
|
||||
using bts;
|
||||
|
||||
using mbts.ui.shell;
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -40,7 +40,7 @@
|
||||
new Dictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData>());
|
||||
|
||||
public VolSurfaceOutput Clone() => new(
|
||||
ProtoBufSerializationHelper.clone_protobuf(volsurface_input),
|
||||
ProtobufSerializationHelper.clone(volsurface_input),
|
||||
new Dictionary<VolSurfaceExpiration, VolCurveOutput>(exp_output_map),
|
||||
new Dictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData>(aux_data_map));
|
||||
|
||||
|
||||
@@ -1,112 +1,191 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using bts.api;
|
||||
using bts.settings;
|
||||
using bts.spark;
|
||||
|
||||
using mbts.spark;
|
||||
|
||||
#nullable enable
|
||||
namespace mbts {
|
||||
[ProtoBuf.ProtoContract()]
|
||||
using bts.api;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.ui.utility;
|
||||
using mbts.utils;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using Spark.Core;
|
||||
using Spark.Core.Collections;
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
[ProtoContract]
|
||||
[Serializable]
|
||||
public class SecurityExpiration : IEquatable<SecurityExpiration> {
|
||||
[ProtoBuf.ProtoMember(1)]
|
||||
private readonly SecurityTuple _sec_tup;
|
||||
[ProtoBuf.ProtoMember(2)]
|
||||
public readonly DateTime expiration;
|
||||
[ProtoBuf.ProtoMember(2)]
|
||||
private readonly Nullable<uint> _id;
|
||||
public readonly static SecurityExpiration empty = new SecurityExpiration(SecurityTuple.empty.security_exchange, SecurityTuple.empty.security_type, SecurityTuple.empty.security_name, DateTime.MinValue);
|
||||
public class SecurityExpiration : IProtobuf<SecurityExpiration> {
|
||||
public readonly static SecurityExpiration empty = new(
|
||||
SecurityTuple.empty.security_exchange,
|
||||
SecurityTuple.empty.security_type,
|
||||
SecurityTuple.empty.security_name,
|
||||
DateTime.MinValue);
|
||||
|
||||
// for ProtoBuf deserialization
|
||||
private SecurityExpiration() { }
|
||||
// for deserialization
|
||||
SecurityExpiration() =>
|
||||
security_tuple = SecurityTuple.empty;
|
||||
|
||||
public SecurityExpiration(Venue exchange, Security.ContractOneofCase type, string symbol, DateTime exp, Nullable<uint> id = null)
|
||||
public SecurityExpiration(
|
||||
Venue exchange,
|
||||
Security.ContractOneofCase type,
|
||||
string symbol,
|
||||
DateTime exp,
|
||||
uint? id = null)
|
||||
: this(exchange, type.security_type(), symbol, exp, id) { }
|
||||
|
||||
public SecurityExpiration(Venue exchange, SecurityType type, string symbol, DateTime exp, Nullable<uint> id = null)
|
||||
: this(new SecurityTuple(type, symbol, exchange), exp, id) { }
|
||||
public SecurityExpiration(
|
||||
Venue exchange, SecurityType type, string symbol, DateTime expiration, uint? id = null)
|
||||
: this(new SecurityTuple(type, symbol, exchange), expiration, id) { }
|
||||
|
||||
public SecurityExpiration(SecurityTuple sec_tup, DateTime exp, Nullable<uint> id = null) {
|
||||
_sec_tup = sec_tup;
|
||||
expiration = exp;
|
||||
_id = id;
|
||||
public SecurityExpiration(
|
||||
SecurityTuple security_tuple, DateTime expiration, uint? id = null) {
|
||||
this.security_tuple = security_tuple;
|
||||
this.expiration = expiration;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public SecurityTuple security_tuple { get { return _sec_tup; } }
|
||||
[ProtoMember(1)]
|
||||
public SecurityTuple security_tuple { get; }
|
||||
|
||||
public SecurityType security_type { get { return _sec_tup.security_type; } }
|
||||
[ProtoMember(2)]
|
||||
public DateTime expiration { get; }
|
||||
|
||||
public string symbol { get { return _sec_tup.security_name; } }
|
||||
[ProtoMember(3)]
|
||||
public uint? id { get; }
|
||||
|
||||
public Venue exchange { get { return _sec_tup.security_exchange; } }
|
||||
public SecurityType security_type => security_tuple?.security_type ?? SecurityType.Unset;
|
||||
public string symbol => security_tuple?.security_name ?? string.Empty;
|
||||
public Venue exchange => security_tuple?.security_exchange ?? Venue.Unset;
|
||||
|
||||
public bool is_empty() { return Equals(empty); }
|
||||
|
||||
public Nullable<uint> id() { return _id; }
|
||||
|
||||
public SecurityExpiration unset_exchange() {
|
||||
return new SecurityExpiration(Venue.Unset, security_type, symbol, expiration);
|
||||
[Flags]
|
||||
public enum Properties {
|
||||
Type = 1,
|
||||
Symbol = 1 << 1,
|
||||
Expiration = 1 << 2,
|
||||
Venue = 1 << 3,
|
||||
Id = 1 << 4
|
||||
}
|
||||
|
||||
public bool Equals(SecurityExpiration other) {
|
||||
if (other != null)
|
||||
return _sec_tup.Equals(other._sec_tup) && expiration.Equals(other.expiration);
|
||||
else
|
||||
return false;
|
||||
public static IEqualityComparer<SecurityExpiration> get_eq_comparer() =>
|
||||
get_eq_comparer(
|
||||
Properties.Type, Properties.Symbol, Properties.Expiration, Properties.Venue);
|
||||
|
||||
public static IEqualityComparer<SecurityExpiration> get_eq_comparer(Properties props) {
|
||||
return EqualityComparerBuilder.create_comparer(
|
||||
EnumHelper.split_flags(props).Select(get_prop_comparer));
|
||||
|
||||
static IEqualityComparer<SecurityExpiration> get_prop_comparer(Properties single_prop) =>
|
||||
single_prop switch {
|
||||
Properties.Type => wrap(s => s.security_type),
|
||||
Properties.Symbol => wrap(s => s.symbol).to_safe(),
|
||||
Properties.Expiration => wrap(s => s.expiration),
|
||||
Properties.Venue => wrap(s => s.exchange),
|
||||
Properties.Id => wrap(s => s.id).to_safe(),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
static IEqualityComparer<SecurityExpiration> wrap<T>(
|
||||
Func<SecurityExpiration, T> selector, IEqualityComparer<T>? comparer = null) =>
|
||||
EqualityComparer.Create(selector, comparer ?? EqualityComparer<T>.Default);
|
||||
}
|
||||
|
||||
#region Object overrides
|
||||
public static IEqualityComparer<SecurityExpiration> get_eq_comparer(params Properties[] hierarchy) =>
|
||||
EqualityComparerBuilder.create(hierarchy.Select(get_eq_comparer)).to_comparer();
|
||||
|
||||
public override int GetHashCode() { return _sec_tup.GetHashCode() ^ expiration.GetHashCode(); }
|
||||
public static IComparer<SecurityExpiration> get_comparer() =>
|
||||
get_comparer(Properties.Venue, Properties.Type, Properties.Symbol, Properties.Expiration);
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
return Equals(obj as SecurityExpiration);
|
||||
public static IComparer<SecurityExpiration> get_comparer(Properties prop) {
|
||||
return prop switch {
|
||||
Properties.Type => ComparerWrapper<SecurityExpiration>.wrap(s => s.security_type),
|
||||
Properties.Symbol => ComparerWrapper<SecurityExpiration>.wrap(s => s.symbol),
|
||||
Properties.Expiration => ComparerWrapper<SecurityExpiration>.wrap(s => s.expiration),
|
||||
Properties.Venue => ComparerWrapper<SecurityExpiration>.wrap(s => s.exchange),
|
||||
Properties.Id => ComparerWrapper<SecurityExpiration>.wrap(s => s.id),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
|
||||
public static bool operator ==(SecurityExpiration x, SecurityExpiration y) {
|
||||
if (Object.ReferenceEquals(x, null)) return Object.ReferenceEquals(y, null);
|
||||
if (Object.ReferenceEquals(y, null)) return false;
|
||||
return x.Equals(y);
|
||||
}
|
||||
public static bool operator !=(SecurityExpiration x, SecurityExpiration y) { return !(x == y); }
|
||||
public static IComparer<SecurityExpiration> get_comparer(params Properties[] hierarchy) =>
|
||||
ComparerBuilder.create(hierarchy.Select(get_comparer)).to_comparer();
|
||||
|
||||
public override string ToString() {
|
||||
return String.Format("{0} {1}", _sec_tup.ToString(), expiration.ToShortDateString());
|
||||
}
|
||||
#endregion
|
||||
public static IComparer<SecurityExpiration> get_exp_based_comparer() =>
|
||||
get_comparer(Properties.Expiration, Properties.Venue, Properties.Type, Properties.Symbol);
|
||||
|
||||
public static int ExpBasedCompare(SecurityExpiration x, SecurityExpiration y) {
|
||||
if (y == null) return 1;
|
||||
if (x == null) return -1;
|
||||
int rv = x.expiration.CompareTo(y.expiration);
|
||||
if (rv == 0)
|
||||
rv = x._sec_tup.CompareTo(y._sec_tup);
|
||||
return rv;
|
||||
}
|
||||
public bool is_empty() => Equals(empty);
|
||||
|
||||
public static int SecBasedCompare(SecurityExpiration x, SecurityExpiration y) {
|
||||
if (y == null) return 1;
|
||||
if (x == null) return -1;
|
||||
int rv = x._sec_tup.CompareTo(y._sec_tup);
|
||||
if (rv == 0)
|
||||
rv = x.expiration.CompareTo(y.expiration);
|
||||
return rv;
|
||||
public SecurityExpiration unset_exchange() =>
|
||||
new(Venue.Unset, security_type, symbol, expiration);
|
||||
|
||||
public SecurityExpiration Clone() =>
|
||||
new(security_tuple.Clone(), expiration, id);
|
||||
|
||||
public bool Equals(SecurityExpiration? other) =>
|
||||
other is not null &&
|
||||
security_tuple.safe_equals(other.security_tuple) &&
|
||||
expiration == other.expiration;
|
||||
|
||||
public override bool Equals(object? obj) =>
|
||||
Equals(obj as SecurityExpiration);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(security_tuple, expiration);
|
||||
|
||||
object ICloneable.Clone() =>
|
||||
Clone();
|
||||
|
||||
public static bool operator ==(SecurityExpiration? x, SecurityExpiration? y) =>
|
||||
x is null ? y is null : x.Equals(y);
|
||||
|
||||
public static bool operator !=(SecurityExpiration x, SecurityExpiration y) =>
|
||||
!(x == y);
|
||||
|
||||
public override string ToString() =>
|
||||
$"{security_tuple} {expiration.ToShortDateString()}";
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public class SecurityExpirationProto : IProtobuf<SecurityExpirationProto> {
|
||||
[ProtoMember(1)]
|
||||
public SecurityTuple? security { get; set; }
|
||||
|
||||
[ProtoMember(2)]
|
||||
public double expiration_oa_date { get; set; }
|
||||
|
||||
public SecurityExpirationProto Clone() =>
|
||||
new() { security = security, expiration_oa_date = expiration_oa_date};
|
||||
|
||||
public bool Equals(SecurityExpirationProto? other) =>
|
||||
other is not null &&
|
||||
security.safe_equals(other.security) &&
|
||||
expiration_oa_date.Equals(other.expiration_oa_date);
|
||||
|
||||
public override bool Equals(object? obj) =>
|
||||
Equals(obj as SecurityExpirationProto);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(security, expiration_oa_date);
|
||||
|
||||
object ICloneable.Clone() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
[ProtoBuf.ProtoContract]
|
||||
public class SecurityExpirationProto {
|
||||
[ProtoBuf.ProtoMember(1)]
|
||||
public SecurityTuple security;
|
||||
|
||||
[ProtoBuf.ProtoMember(2)]
|
||||
public double expiration_oa_date;
|
||||
public static class SecurityExpirationExtensions {
|
||||
public static SecurityExpiration with(
|
||||
this SecurityExpiration sec_exp,
|
||||
Venue? exchange = null,
|
||||
SecurityType? security_type = null,
|
||||
string? symbol = null,
|
||||
DateTime? expiration = null,
|
||||
Optional<uint> id = default) => new(
|
||||
exchange ?? sec_exp.exchange, security_type ?? sec_exp.security_type,
|
||||
symbol ?? sec_exp.symbol,
|
||||
expiration ?? sec_exp.expiration,
|
||||
id.has_value ? id : sec_exp.id);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using bts.api;
|
||||
using bts.settings;
|
||||
using bts.spark;
|
||||
|
||||
using mbts.spark;
|
||||
|
||||
#nullable enable
|
||||
namespace mbts {
|
||||
using bts.api;
|
||||
|
||||
using Spark.Core.Data;
|
||||
|
||||
using System;
|
||||
|
||||
public class SecurityStrike : IEquatable<SecurityStrike> {
|
||||
public readonly SecurityExpiration expiration;
|
||||
public readonly double strike;
|
||||
public readonly Tuple<UInt32?, UInt32?> call_put_id;
|
||||
public SecurityStrike(SecurityExpiration expiration, double strike,
|
||||
Tuple<UInt32?, UInt32?> call_put_id = null) {
|
||||
public SecurityStrike(
|
||||
SecurityExpiration expiration, double strike, CallPutTuple<uint?> call_put_id = default) {
|
||||
this.expiration = expiration;
|
||||
this.strike = strike;
|
||||
this.call_put_id = call_put_id;
|
||||
}
|
||||
|
||||
public SecurityStrike(string symbol, DateTime exp, double strike,
|
||||
Tuple<UInt32?, UInt32?> call_put_id = null)
|
||||
: this(new SecurityExpiration(
|
||||
Venue.Unset, SecurityType.Option, symbol, exp), strike, call_put_id) { }
|
||||
public SecurityStrike(
|
||||
string symbol, DateTime exp, double strike, CallPutTuple<uint?> call_put_id = default)
|
||||
: this(new(Venue.Unset, SecurityType.Option, symbol, exp), strike, call_put_id) { }
|
||||
|
||||
public bool Equals(SecurityStrike other) {
|
||||
if (other != null)
|
||||
return expiration.Equals(other.expiration) && strike.Equals(other.strike);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
public SecurityExpiration expiration { get; }
|
||||
public double strike { get; }
|
||||
public CallPutTuple<uint?> call_put_id { get; }
|
||||
|
||||
public override int GetHashCode() { return expiration.GetHashCode() ^ strike.GetHashCode(); }
|
||||
/// TODO: figure out why <see cref="call_put_id"/> is excluded from equality logic
|
||||
/// (was it an accident, or intentional? if the latter, why?)
|
||||
public bool Equals(SecurityStrike? other) =>
|
||||
other is not null &&
|
||||
expiration.Equals(other.expiration) &&
|
||||
strike.Equals(other.strike);
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
return Equals(obj as SecurityStrike);
|
||||
}
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(expiration, strike);
|
||||
|
||||
public static bool operator ==(SecurityStrike x, SecurityStrike y) {
|
||||
if ((object)x == null) return (object)y == null;
|
||||
return x.Equals(y);
|
||||
}
|
||||
public override bool Equals(object? obj) =>
|
||||
Equals(obj as SecurityStrike);
|
||||
|
||||
public static bool operator !=(SecurityStrike x, SecurityStrike y) { return !(x == y); }
|
||||
public static bool operator ==(SecurityStrike x, SecurityStrike y) =>
|
||||
x is null ? y is null : x.Equals(y);
|
||||
|
||||
public override string ToString() {
|
||||
return String.Format("{0} {1}", expiration.ToString(), strike.ToString());
|
||||
}
|
||||
public static bool operator !=(SecurityStrike x, SecurityStrike y) =>
|
||||
!(x == y);
|
||||
|
||||
public SecurityStrike unset_exchange() { return new SecurityStrike(expiration.unset_exchange(), strike); }
|
||||
public override string ToString() =>
|
||||
$"{expiration} {strike}";
|
||||
|
||||
public SecurityStrike unset_exchange() =>
|
||||
new(expiration.with(exchange: Venue.Unset), strike);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,29 @@ namespace mbts.analytics {
|
||||
/// they all in a way "derive" from core
|
||||
[ProtoContract]
|
||||
public class VolSurfaceSettings {
|
||||
public static VolSurfaceSettings Default(string name) => new() {
|
||||
core_settings = new VolSurfaceCoreSettings {
|
||||
vol_surface_name = name,
|
||||
vol_surface_model = VolSurfaceEnums.VolSurfaceModel.Polynomial,
|
||||
call_rotation = new() { strike_vol_movement_pairs = new() },
|
||||
put_rotation = new() { strike_vol_movement_pairs = new() },
|
||||
strangle = new() { strike_vol_movement_pairs = new() },
|
||||
full_rotation = new() { strike_vol_movement_pairs = new() },
|
||||
atm_shift = new() { strike_vol_movement_pairs = new() },
|
||||
symbols = new(),
|
||||
symbol_structure_list = new(),
|
||||
wing_settings = new() {
|
||||
explicit_slope_wing_settings = new(),
|
||||
implicit_slope_wing_settings = new(),
|
||||
onepoint_slope_wing_settings = new()
|
||||
},
|
||||
unset_expiration_calculation_settings = new(),
|
||||
volpath_settings = new(),
|
||||
safety_limits = new(),
|
||||
},
|
||||
polynomial_model_settings = new()
|
||||
};
|
||||
|
||||
[ProtoMember(10)]
|
||||
public VolSurfaceCoreSettings core_settings;
|
||||
[ProtoMember(15)]
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
using System;
|
||||
using bts.api;
|
||||
using bts.settings;
|
||||
using bts.spark;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.spark;
|
||||
using mbts.ui.converters;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using bts.api;
|
||||
using bts.settings;
|
||||
using bts.spark;
|
||||
|
||||
using mbts.spark;
|
||||
using mbts.ui.converters;
|
||||
using bts.utils;
|
||||
|
||||
namespace mbts.analytics {
|
||||
/// <summary>
|
||||
/// An expiration in the Vol Surface is expressed
|
||||
@@ -26,7 +26,13 @@ namespace mbts.analytics {
|
||||
public class VolSurfaceExpiration : IEquatable<VolSurfaceExpiration>, IComparable<VolSurfaceExpiration> {
|
||||
public VolSurfaceExpiration() : this(string.Empty, default(DateTime)) { }
|
||||
|
||||
public VolSurfaceExpiration(string symbol, DateTime expiration) {
|
||||
public VolSurfaceExpiration(string symbol, DateTime expiration)
|
||||
:
|
||||
this(bts.api.SecurityType.Option, symbol, expiration) {
|
||||
}
|
||||
|
||||
public VolSurfaceExpiration(bts.api.SecurityType security_type, string symbol, DateTime expiration) {
|
||||
this.security_type = security_type;
|
||||
this.symbol = symbol;
|
||||
this.expiration = expiration;
|
||||
}
|
||||
@@ -36,28 +42,31 @@ namespace mbts.analytics {
|
||||
expiration = exp.expiration;
|
||||
}
|
||||
|
||||
public SecurityExpiration to_security_expiration() {
|
||||
// TODO
|
||||
return new SecurityExpiration(Venue.Unset, SecurityType.Option, symbol, expiration);
|
||||
}
|
||||
public SecurityExpiration to_security_expiration(
|
||||
Venue exchange = Venue.Unset, SecurityType type = SecurityType.Unset) =>
|
||||
new(exchange, security_type, symbol, expiration);
|
||||
|
||||
[ProtoBuf.ProtoMember(10)]
|
||||
public string symbol;
|
||||
[ProtoBuf.ProtoMember(20)]
|
||||
public DateTime expiration;
|
||||
[ProtoBuf.ProtoMember(30)]
|
||||
public bts.api.SecurityType security_type = bts.api.SecurityType.Option;
|
||||
|
||||
|
||||
public bool Equals(VolSurfaceExpiration other) {
|
||||
return other != null && symbol.Equals(other.symbol) && expiration.Equals(other.expiration);
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return symbol.GetHashCode() ^ expiration.GetHashCode(); }
|
||||
public override int GetHashCode() { return security_type.GetHashCode() ^ symbol.GetHashCode() ^ expiration.GetHashCode(); }
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
return Equals(obj as VolSurfaceExpiration);
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return String.Format("{0} {1}", symbol, expiration.ToShortDateString());
|
||||
return String.Format("{0} {1} {2}",
|
||||
security_type.ToString().ToUpper().First(), symbol, expiration.ToShortDateString());
|
||||
}
|
||||
|
||||
public int CompareTo(VolSurfaceExpiration other) {
|
||||
@@ -65,18 +74,19 @@ namespace mbts.analytics {
|
||||
int rv = expiration.CompareTo(other.expiration);
|
||||
return rv != 0 ? rv : symbol.CompareTo(other.symbol);
|
||||
}
|
||||
|
||||
public double diff_days(VolSurfaceExpiration exp_other) {
|
||||
TimeSpan ts = expiration - exp_other.expiration;
|
||||
return ts.TotalDays;
|
||||
}
|
||||
}
|
||||
|
||||
public static class VolSurfaceExpirationExtensions {
|
||||
public static SecurityExpiration ToSecurityExp(this VolSurfaceExpiration vs_exp) {
|
||||
var type = SecurityType.Unset;
|
||||
if (!string.IsNullOrWhiteSpace(vs_exp.symbol)) {
|
||||
if (Char.IsLower(vs_exp.symbol.First())) type = SecurityType.Option;
|
||||
else if (Char.IsUpper(vs_exp.symbol.First())) type = SecurityType.Future;
|
||||
}
|
||||
return new SecurityExpiration(Venue.Unset, type, vs_exp.symbol, vs_exp.expiration);
|
||||
}
|
||||
public static SecurityExpiration ToSecurityExp(
|
||||
this VolSurfaceExpiration vs_exp, SecurityType type) =>
|
||||
new(Venue.Unset, type, vs_exp.symbol, vs_exp.expiration);
|
||||
}
|
||||
|
||||
public class VolSurfaceStrikeMap {
|
||||
public readonly IDictionary<VolSurfaceExpiration, IEnumerable<double>> strike_map = null;
|
||||
public VolSurfaceStrikeMap(IEnumerable<string> option_names, SystemContractData sc_data) {
|
||||
|
||||
@@ -943,7 +943,15 @@ namespace mbts.analytics {
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region inverse contracts
|
||||
// Bitcoin contracts, for example, where the strike is in USD, and the theo
|
||||
// needs to be in terms of the underlying contract
|
||||
public static double normalize_theo(double theo, double fwd) {
|
||||
return fwd == 0 ? Double.NaN : (theo / fwd);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other Pricing Utilities
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -19,9 +21,11 @@ namespace mbts.analytics
|
||||
{
|
||||
HashSet<VolSurfaceExpiration> vs_exp_map = new HashSet<VolSurfaceExpiration>(vs_input.surface_parameters.curve_parameters_map.Select(t => t.Item1)),
|
||||
sys_exp_map = new HashSet<VolSurfaceExpiration>(system_exp_list);
|
||||
HashSet<VolSurfaceExpiration> deleted_exps, added_exps;
|
||||
if (VolSurfaceUtilityFunctions.compare_hashsets(sys_exp_map, vs_exp_map, out deleted_exps, out added_exps))
|
||||
{
|
||||
sys_exp_map.difference(
|
||||
vs_exp_map,
|
||||
out HashSet<VolSurfaceExpiration> deleted_exps,
|
||||
out HashSet<VolSurfaceExpiration> added_exps);
|
||||
if (deleted_exps.Any() || added_exps.Any()) {
|
||||
VolSurfaceInput rv = VolSurfaceUtilityFunctions.clone_proto(vs_input);
|
||||
rv.surface_parameters.curve_parameters_map = rv.surface_parameters.curve_parameters_map ?? new List<Tuple<VolSurfaceExpiration, VolCurveParameters>>();
|
||||
rv.surface_parameters.curve_parameters_map.RemoveAll(t => deleted_exps.Contains(t.Item1));
|
||||
@@ -100,7 +104,11 @@ namespace mbts.analytics
|
||||
else if (vs_settings.core_settings.vol_surface_model == VolSurfaceEnums.VolSurfaceModel.Polynomial)
|
||||
{
|
||||
rv.spline_model_parameters = null;
|
||||
rv.polynomial_model_parameters = rv.polynomial_model_parameters ?? new PolynomialModelVolCurveParameters() { atm_vol = Double.NaN, put_points = new List<Tuple<double, double>>(), call_points = new List<Tuple<double, double>>() };
|
||||
rv.polynomial_model_parameters ??= new PolynomialModelVolCurveParameters() {
|
||||
atm_vol = double.NaN
|
||||
};
|
||||
rv.polynomial_model_parameters.put_points ??= new();
|
||||
rv.polynomial_model_parameters.call_points ??= new();
|
||||
if (rv.polynomial_model_parameters.put_points.Count != vs_settings.polynomial_model_settings.n_put_points)
|
||||
rv.polynomial_model_parameters.put_points = _sync_volpoints_to_settings(rv.polynomial_model_parameters.put_points, false, vs_settings.polynomial_model_settings.strike_axis, (int)vs_settings.polynomial_model_settings.n_put_points).ToList();
|
||||
if (rv.polynomial_model_parameters.call_points.Count != vs_settings.polynomial_model_settings.n_call_points)
|
||||
@@ -228,10 +236,8 @@ namespace mbts.analytics
|
||||
return vs_input != null ? get_symbols(vs_input.surface_settings) : new string[] { };
|
||||
}
|
||||
|
||||
public static IEnumerable<string> get_symbols(VolSurfaceSettings vs_settings)
|
||||
{
|
||||
return vs_settings.core_settings.symbol_pricing_model_map.Select(i => i.Item1);
|
||||
}
|
||||
public static IEnumerable<string> get_symbols(VolSurfaceSettings vs_settings) =>
|
||||
vs_settings.core_settings.symbol_pricing_model_map.empty_if_null().Select(i => i.Item1);
|
||||
|
||||
public static VolCurveParameters get_curve_parameters(VolSurfaceInput vs_input, VolSurfaceExpiration exp)
|
||||
{
|
||||
@@ -674,5 +680,60 @@ namespace mbts.analytics
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data copying
|
||||
|
||||
public static bool exp_has_input(VolSurfaceSettings vs_settings, VolCurveParameters exp_params) {
|
||||
if (exp_params == null || vs_settings == null)
|
||||
return false;
|
||||
double atm_vol = get_atm_vol(vs_settings, exp_params);
|
||||
double ref_fwd = exp_params.core_parameters.ref_forward;
|
||||
return !Double.IsNaN(atm_vol) && !Double.IsNaN(ref_fwd);
|
||||
}
|
||||
|
||||
public static VolSurfaceExpiration find_nearest_populated_exp(
|
||||
VolSurfaceInput vs_input, VolSurfaceExpiration vs_exp) {
|
||||
VolCurveParameters exp_params = get_curve_parameters(vs_input, vs_exp);
|
||||
if (exp_has_input(vs_input.surface_settings, exp_params))
|
||||
return vs_exp;
|
||||
VolSurfaceExpiration rv = null;
|
||||
double rv_diff_days = Double.MaxValue;
|
||||
foreach (var kv in vs_input.surface_parameters.curve_parameters_map) {
|
||||
var this_exp = kv.Item1;
|
||||
var this_exp_params = kv.Item2;
|
||||
if (exp_has_input(vs_input.surface_settings, this_exp_params)) {
|
||||
double this_exp_diff_days = Math.Abs(vs_exp.diff_days(this_exp));
|
||||
if (this_exp_diff_days < rv_diff_days) {
|
||||
rv = this_exp;
|
||||
rv_diff_days = this_exp_diff_days;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Copies the empty exps from closest neighbor
|
||||
public static VolSurfaceInput populate_empty_expirations(VolSurfaceInput vs_input) {
|
||||
VolSurfaceInput rv = Spark.Core.Protobuf.ProtobufSerializationHelper.clone(vs_input);
|
||||
rv.surface_parameters.curve_parameters_map.Clear();
|
||||
foreach (var kv in vs_input.surface_parameters.curve_parameters_map) {
|
||||
var vs_exp = kv.Item1;
|
||||
var exp_params = kv.Item2;
|
||||
if (!exp_has_input(vs_input.surface_settings, exp_params)) {
|
||||
VolSurfaceExpiration np_exp = find_nearest_populated_exp(vs_input, vs_exp);
|
||||
if (np_exp != null) {
|
||||
var np_exp_params = get_curve_parameters(vs_input, np_exp);
|
||||
if (np_exp_params != null) {
|
||||
exp_params = Spark.Core.Protobuf.ProtobufSerializationHelper.clone(np_exp_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
rv.surface_parameters.curve_parameters_map.Add(
|
||||
new Tuple<VolSurfaceExpiration, VolCurveParameters>(vs_exp, exp_params));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
namespace mbts.analytics {
|
||||
using bts.utils;
|
||||
|
||||
using mbts.spark.filters;
|
||||
|
||||
using System;
|
||||
|
||||
public class VolSurfaceDriverTheo {
|
||||
public static readonly VolSurfaceDriverTheo empty = new(
|
||||
SecurityExpiration.empty, SecurityExpiration.empty);
|
||||
|
||||
public readonly SecurityExpiration exp;
|
||||
public readonly SecurityExpiration driver_exp;
|
||||
public readonly double market_price;
|
||||
public readonly double driver_market_price;
|
||||
public readonly double roll;
|
||||
public readonly double theo;
|
||||
public readonly double delta;
|
||||
public readonly double settlement_price;
|
||||
public readonly double settlement_theo;
|
||||
public readonly double settlement_delta;
|
||||
|
||||
public VolSurfaceDriverTheo(
|
||||
SecurityExpiration exp,
|
||||
SecurityExpiration driver_exp,
|
||||
double market_price = double.NaN,
|
||||
double driver_market_price = double.NaN,
|
||||
double roll = double.NaN,
|
||||
double theo = double.NaN,
|
||||
double delta = double.NaN,
|
||||
double settlement_price = double.NaN,
|
||||
double settlement_theo = double.NaN,
|
||||
double settlement_delta = double.NaN
|
||||
) {
|
||||
this.exp = exp;
|
||||
this.driver_exp = driver_exp;
|
||||
this.market_price = market_price;
|
||||
this.driver_market_price = driver_market_price;
|
||||
this.roll = roll;
|
||||
this.theo = theo;
|
||||
this.delta = delta;
|
||||
this.settlement_price = settlement_price;
|
||||
this.settlement_theo = settlement_theo;
|
||||
this.settlement_delta = settlement_delta;
|
||||
}
|
||||
|
||||
public bool is_settlement_populated {
|
||||
get {
|
||||
bool non_populated = double.IsNaN(settlement_price) ||
|
||||
Math.Abs(settlement_price) < 0.0000001;
|
||||
return !non_populated;
|
||||
}
|
||||
}
|
||||
|
||||
public double effective_theo => is_settlement_populated ? settlement_price : theo;
|
||||
public double effective_delta => is_settlement_populated ? 0 : delta;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -5,6 +5,9 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using bts;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
namespace mbts.analytics
|
||||
{
|
||||
@@ -152,12 +155,8 @@ namespace mbts.analytics
|
||||
out double adjusted_ref_fwd,
|
||||
out double adjusted_ref_vol)
|
||||
{
|
||||
IComparer<ControlPoint> comp = VolSurfaceUtilityFunctions.get_comparer<ControlPoint>(
|
||||
(cp1, cp2) =>
|
||||
{
|
||||
double d1 = Math.Abs(cp1.standard_strike), d2 = Math.Abs(cp2.standard_strike);
|
||||
return (Double.IsNaN(d1) ? Double.PositiveInfinity : d1).CompareTo((Double.IsNaN(d2) ? Double.PositiveInfinity : d2));
|
||||
});
|
||||
var comp = new ComparerBuilder<ControlPoint>()
|
||||
.to_comparer(cp => cp.standard_strike.abs().if_nan(double.PositiveInfinity));
|
||||
adjusted_atm_vol = input_atm_vol + parallel_curve_move + (is_rebuild ? volpath_move : 0.0);
|
||||
adjusted_put_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Put).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
|
||||
adjusted_call_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Call).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
|
||||
@@ -306,12 +305,8 @@ namespace mbts.analytics
|
||||
IEnumerable<ControlPoint> calculated_controlpoints)
|
||||
{
|
||||
curve_parameters = VolSurfaceUtilityFunctions.clone_proto(curve_parameters);
|
||||
IComparer<ControlPoint> comp = VolSurfaceUtilityFunctions.get_comparer<ControlPoint>(
|
||||
(cp1, cp2) =>
|
||||
{
|
||||
double d1 = Math.Abs(cp1.standard_strike), d2 = Math.Abs(cp2.standard_strike);
|
||||
return (Double.IsNaN(d1) ? Double.PositiveInfinity : d1).CompareTo((Double.IsNaN(d2) ? Double.PositiveInfinity : d2));
|
||||
});
|
||||
var comp = new ComparerBuilder<ControlPoint>()
|
||||
.to_comparer(cp => cp.standard_strike.abs().if_nan(double.PositiveInfinity));
|
||||
var adjusted_put_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Put).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
|
||||
var adjusted_call_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Call).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
|
||||
if (surface_settings.core_settings.vol_surface_model == VolSurfaceEnums.VolSurfaceModel.CubicSpline)
|
||||
@@ -467,4 +462,4 @@ namespace mbts.analytics
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel;
|
||||
namespace mbts.analytics {
|
||||
using bts.api.analytics;
|
||||
|
||||
namespace mbts.analytics
|
||||
{
|
||||
/// move this out later
|
||||
public enum VolSurfaceGreeks
|
||||
{
|
||||
/* *********************Primary Greeks*********************/
|
||||
Vol,
|
||||
Moneyness,
|
||||
Theo,
|
||||
Delta,
|
||||
[Description("BSM Delta")]
|
||||
BSMDelta,
|
||||
FlatVolDelta,
|
||||
Vega,
|
||||
[Description("BSM Vega")]
|
||||
BSMVega,
|
||||
AdjustedVega, /// adjusted_vega = vega * (atm_vega/n_days_atm_vega)
|
||||
Theta,
|
||||
AdjustedTheta, /// what is that ? (its in slide)
|
||||
RollRho,
|
||||
DiscountRho,
|
||||
TimeValue,
|
||||
/* *********************Second Order*********************/
|
||||
Gamma,
|
||||
[Description("BSM Gamma")]
|
||||
BSMGamma,
|
||||
OEV,
|
||||
[Description("BSM OEV")]
|
||||
BSMOEV,
|
||||
Vanna,
|
||||
Volga,
|
||||
Charm,
|
||||
[Description("Vol/Und")]
|
||||
DVolDUnd,
|
||||
[Description("Vol²/DUnd²")]
|
||||
D2VolDUnd2,
|
||||
/* *********************Curve Operations******************/
|
||||
[Description("Price/DRR")]
|
||||
DPriceDRiskReversal,
|
||||
[Description("Price/Strangle")]
|
||||
DPriceDStrangle,
|
||||
[Description("Price/Put Tilt")]
|
||||
DPriceDPutTilt,
|
||||
[Description("Price/Call Tilt")]
|
||||
DPriceDCallTilt,
|
||||
/* *********************Risk*******************************/
|
||||
[Description("PnL")]
|
||||
PNL,
|
||||
ExpirationDelta
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[ProtoBuf.ProtoContract(Name = "VolSurfaceStrikeTheo")]
|
||||
public class VolSurfaceStrikeTheo
|
||||
{
|
||||
public class VolSurfaceStrikeTheo {
|
||||
[ProtoBuf.ProtoMember(10)]
|
||||
public DateTime exp;
|
||||
[ProtoBuf.ProtoMember(20)]
|
||||
@@ -73,9 +19,8 @@ namespace mbts.analytics
|
||||
}
|
||||
|
||||
[ProtoBuf.ProtoContract(Name = "VolSurfaceSymbolTheos")]
|
||||
public class VolSurfaceSymbolTheos
|
||||
{
|
||||
public class VolSurfaceSymbolTheos {
|
||||
[ProtoBuf.ProtoMember(10)]
|
||||
public List<VolSurfaceStrikeTheo> all_theos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
namespace mbts.analytics {
|
||||
using bts.api.analytics;
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace mbts.analytics
|
||||
{
|
||||
/// Computes greeks from VolMatrix
|
||||
public class VolSurfaceTheoCalculator
|
||||
{
|
||||
@@ -26,27 +25,27 @@ namespace mbts.analytics
|
||||
{VolSurfaceGreeks.Moneyness, (volmat, is_call) => volmat.standard_strike},
|
||||
{VolSurfaceGreeks.Theo, (volmat, is_call) => compute_theo (volmat, is_call)},
|
||||
{VolSurfaceGreeks.Delta, (volmat, is_call) => compute_delta (volmat, is_call)},
|
||||
{VolSurfaceGreeks.BSMDelta, (volmat, is_call) => compute_bsm_delta (volmat, is_call)},
|
||||
{VolSurfaceGreeks.Bsmdelta, (volmat, is_call) => compute_bsm_delta (volmat, is_call)},
|
||||
{VolSurfaceGreeks.FlatVolDelta, (volmat, is_call) => compute_flatvol_delta (volmat, is_call)},
|
||||
{VolSurfaceGreeks.Vega, (volmat, is_call) => compute_vega (volmat, is_call)},
|
||||
{VolSurfaceGreeks.BSMVega, (volmat, is_call) => compute_bsm_vega (volmat)},
|
||||
{VolSurfaceGreeks.Bsmvega, (volmat, is_call) => compute_bsm_vega (volmat)},
|
||||
{VolSurfaceGreeks.Theta, (volmat, is_call) => compute_theta (volmat, is_call)},
|
||||
{VolSurfaceGreeks.TimeValue, (volmat, is_call) => compute_time_value (volmat, is_call)},
|
||||
|
||||
{VolSurfaceGreeks.Gamma, (volmat, is_call) => compute_gamma (volmat, is_call)},
|
||||
{VolSurfaceGreeks.BSMGamma, (volmat, is_call) => compute_bsm_gamma (volmat)},
|
||||
{VolSurfaceGreeks.OEV, (volmat, is_call) => compute_oev (volmat, is_call)},
|
||||
{VolSurfaceGreeks.BSMOEV, (volmat, is_call) => compute_bsm_oev (volmat, is_call)},
|
||||
{VolSurfaceGreeks.Bsmgamma, (volmat, is_call) => compute_bsm_gamma (volmat)},
|
||||
{VolSurfaceGreeks.Oev, (volmat, is_call) => compute_oev (volmat, is_call)},
|
||||
{VolSurfaceGreeks.Bsmoev, (volmat, is_call) => compute_bsm_oev (volmat, is_call)},
|
||||
{VolSurfaceGreeks.Vanna, (volmat, is_call) => compute_vanna (volmat, is_call)},
|
||||
{VolSurfaceGreeks.Volga, (volmat, is_call) => compute_volga (volmat, is_call)},
|
||||
{VolSurfaceGreeks.Charm, (volmat, is_call) => compute_charm (volmat, is_call)},
|
||||
{VolSurfaceGreeks.DVolDUnd, (volmat, is_call) => compute_dVolDUnd (volmat)},
|
||||
{VolSurfaceGreeks.D2VolDUnd2, (volmat, is_call) => compute_d2VolDUnd2 (volmat)},
|
||||
{VolSurfaceGreeks.DvolDund, (volmat, is_call) => compute_dVolDUnd (volmat)},
|
||||
{VolSurfaceGreeks.D2VolDund2, (volmat, is_call) => compute_d2VolDUnd2 (volmat)},
|
||||
|
||||
{VolSurfaceGreeks.DPriceDRiskReversal, (volmat, is_call) => compute_dPriceDRiskReversal (volmat, is_call)},
|
||||
{VolSurfaceGreeks.DPriceDStrangle, (volmat, is_call) => compute_dPriceDStrangle (volmat, is_call)},
|
||||
{VolSurfaceGreeks.DPriceDPutTilt, (volmat, is_call) => compute_dPriceDPutTilt (volmat, is_call)},
|
||||
{VolSurfaceGreeks.DPriceDCallTilt, (volmat, is_call) => compute_dPriceDCallTilt (volmat, is_call)},
|
||||
{VolSurfaceGreeks.DpriceDriskReversal, (volmat, is_call) => compute_dPriceDRiskReversal (volmat, is_call)},
|
||||
{VolSurfaceGreeks.DpriceDstrangle, (volmat, is_call) => compute_dPriceDStrangle (volmat, is_call)},
|
||||
{VolSurfaceGreeks.DpriceDputTilt, (volmat, is_call) => compute_dPriceDPutTilt (volmat, is_call)},
|
||||
{VolSurfaceGreeks.DpriceDcallTilt, (volmat, is_call) => compute_dPriceDCallTilt (volmat, is_call)},
|
||||
|
||||
};
|
||||
}
|
||||
@@ -443,4 +442,4 @@ namespace mbts.analytics
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +1,72 @@
|
||||
using System;
|
||||
|
||||
using bts.api;
|
||||
using bts.api.analytics;
|
||||
|
||||
#nullable enable
|
||||
namespace mbts.analytics {
|
||||
using bts.api.analytics;
|
||||
using bts.utils;
|
||||
|
||||
using mbts.spark;
|
||||
|
||||
using System;
|
||||
|
||||
[Serializable]
|
||||
public class AnalyticsExpirationParameters : IEquatable<AnalyticsExpirationParameters> {
|
||||
public readonly SecurityExpiration security,
|
||||
driver_security,
|
||||
deliverable_security,
|
||||
roll_schedule_expiration;
|
||||
public readonly DriverCalculationType driver_calc_type =
|
||||
DriverCalculationType.Direct;
|
||||
public readonly double roll_target, riskless_rate, settlement_price;
|
||||
public readonly double driver_addend, driver_factor,
|
||||
driver_translation_target, delta_beta, vega_beta;
|
||||
public static readonly AnalyticsExpirationParameters empty =
|
||||
new(
|
||||
SecurityExpiration.empty,
|
||||
null,
|
||||
SecurityExpiration.empty,
|
||||
SecurityExpiration.empty,
|
||||
double.NaN,
|
||||
double.NaN,
|
||||
double.NaN,
|
||||
double.NaN,
|
||||
double.NaN);
|
||||
|
||||
public static AnalyticsExpirationParameters empty =
|
||||
new AnalyticsExpirationParameters(SecurityExpiration.empty,
|
||||
SecurityExpiration.empty,
|
||||
SecurityExpiration.empty,
|
||||
SecurityExpiration.empty,
|
||||
Double.NaN, Double.NaN, Double.NaN,
|
||||
Double.NaN, Double.NaN);
|
||||
public readonly ExpirationDriverImmutable driver;
|
||||
public readonly double roll_target;
|
||||
public readonly double riskless_rate;
|
||||
public readonly double settlement_price;
|
||||
public readonly double driver_addend;
|
||||
public readonly double driver_factor;
|
||||
public readonly double driver_translation_target;
|
||||
public readonly double delta_beta;
|
||||
public readonly double vega_beta;
|
||||
|
||||
readonly bts.api.domain.SecurityExpirationImmutable _security;
|
||||
readonly bts.api.domain.SecurityExpirationImmutable _deliverable;
|
||||
readonly bts.api.domain.SecurityExpirationImmutable _roll_schedule;
|
||||
|
||||
public AnalyticsExpirationParameters(
|
||||
SecurityExpiration this_security,
|
||||
SecurityExpiration this_driver_security,
|
||||
SecurityExpiration this_deliverable_security,
|
||||
SecurityExpiration this_roll_schedule_expiration,
|
||||
double this_roll_target, double this_riskless_rate,
|
||||
double this_settlement_price, double this_delta_beta,
|
||||
double this_vega_beta) {
|
||||
security = this_security;
|
||||
driver_security = this_driver_security ?? SecurityExpiration.empty;
|
||||
deliverable_security = this_deliverable_security ?? SecurityExpiration.empty;
|
||||
roll_schedule_expiration = this_roll_schedule_expiration ??
|
||||
SecurityExpiration.empty;
|
||||
roll_target = this_roll_target;
|
||||
riskless_rate = this_riskless_rate;
|
||||
settlement_price = this_settlement_price;
|
||||
delta_beta = this_delta_beta;
|
||||
vega_beta = this_vega_beta;
|
||||
SecurityExpiration security,
|
||||
ExpirationDriverImmutable? driver,
|
||||
SecurityExpiration? deliverable_security,
|
||||
SecurityExpiration? roll_schedule_expiration,
|
||||
double roll_target,
|
||||
double riskless_rate,
|
||||
double settlement_price,
|
||||
double delta_beta,
|
||||
double vega_beta
|
||||
) {
|
||||
_security = security.to_api_sec_expi();
|
||||
deliverable_security ??= SecurityExpiration.empty;
|
||||
roll_schedule_expiration ??= SecurityExpiration.empty;
|
||||
|
||||
this.driver = driver ?? new(new() {
|
||||
TimeWeightedInterpolated = new()
|
||||
});
|
||||
_deliverable = deliverable_security.to_api_sec_expi();
|
||||
_roll_schedule = roll_schedule_expiration.to_api_sec_expi();
|
||||
this.roll_target = roll_target;
|
||||
this.riskless_rate = riskless_rate;
|
||||
this.settlement_price = settlement_price;
|
||||
this.delta_beta = delta_beta;
|
||||
this.vega_beta = vega_beta;
|
||||
}
|
||||
|
||||
public AnalyticsExpirationParameters(ExpirationParameterEntryImmutable db_i) {
|
||||
Func<ExpirationImmutable, DateTime> to_dt = (ExpirationImmutable e) =>
|
||||
new DateTime((int)e.ExpirationYear, (int)e.ExpirationMonth,
|
||||
(int)e.ExpirationDay);
|
||||
security = new SecurityExpiration(db_i.Exchange,
|
||||
db_i.SecurityType, db_i.Symbol, to_dt(db_i.Expiration));
|
||||
driver_calc_type = db_i.DriverCalc;
|
||||
driver_security = new SecurityExpiration(db_i.DriverExchange,
|
||||
db_i.DriverSecurityType, db_i.DriverSymbol,
|
||||
to_dt(db_i.DriverExpiration));
|
||||
deliverable_security = new SecurityExpiration(db_i.DeliverableExchange,
|
||||
db_i.DeliverableSecurityType, db_i.DeliverableSymbol,
|
||||
to_dt(db_i.DeliverableExpiration));
|
||||
roll_schedule_expiration = new SecurityExpiration(db_i.RollScheduleExchange,
|
||||
db_i.RollScheduleSecurityType, db_i.RollScheduleSymbol,
|
||||
to_dt(db_i.RollScheduleExpiration));
|
||||
_security = db_i.SecurityExpiration;
|
||||
_deliverable = db_i.Deliverable;
|
||||
_roll_schedule = db_i.RollSchedule;
|
||||
driver = db_i.Driver;
|
||||
roll_target = db_i.RollTarget;
|
||||
riskless_rate = db_i.RisklessRate;
|
||||
settlement_price = db_i.SettlementPrice;
|
||||
@@ -67,66 +74,41 @@ namespace mbts.analytics {
|
||||
vega_beta = db_i.VegaBeta;
|
||||
}
|
||||
|
||||
public bts.api.analytics.ExpirationParameterEntry to_exp_param_entry() {
|
||||
Func<DateTime, Expiration> to_exp = (DateTime e) => {
|
||||
Expiration rv = new Expiration();
|
||||
rv.ExpirationDay = (uint)e.Day;
|
||||
rv.ExpirationMonth = (uint)e.Month;
|
||||
rv.ExpirationYear = (uint)e.Year;
|
||||
return rv;
|
||||
public SecurityExpiration security => _security.to_sec_exp();
|
||||
public SecurityExpiration driver_security => driver.HasSecurity ?
|
||||
driver.Security.to_sec_exp() : SecurityExpiration.empty;
|
||||
public SecurityExpiration deliverable_security => _deliverable.to_sec_exp();
|
||||
public SecurityExpiration roll_schedule_expiration => _roll_schedule.to_sec_exp();
|
||||
|
||||
public ExpirationParameterEntry to_exp_param_entry() =>
|
||||
new() {
|
||||
SecurityExpiration = _security.CloneToMutable(),
|
||||
Driver = driver.CloneToMutable(),
|
||||
Deliverable = _deliverable.CloneToMutable(),
|
||||
RollSchedule = _roll_schedule.CloneToMutable(),
|
||||
RollTarget = roll_target,
|
||||
RisklessRate = riskless_rate,
|
||||
SettlementPrice = settlement_price,
|
||||
DeltaBeta = delta_beta,
|
||||
VegaBeta = vega_beta
|
||||
};
|
||||
bts.api.analytics.ExpirationParameterEntry rv = new ExpirationParameterEntry();
|
||||
rv.SecurityType = security.security_type;
|
||||
rv.Symbol = security.symbol;
|
||||
rv.Expiration = to_exp(security.expiration);
|
||||
rv.Exchange = security.exchange;
|
||||
|
||||
rv.DriverSecurityType = driver_security.security_type;
|
||||
rv.DriverSymbol = driver_security.symbol;
|
||||
rv.DriverExpiration = to_exp(driver_security.expiration);
|
||||
rv.DriverExchange = driver_security.exchange;
|
||||
public bool Equals(AnalyticsExpirationParameters? other) =>
|
||||
other is not null &&
|
||||
security.Equals(other.security) &&
|
||||
driver_security.safe_equals(other.driver_security) &&
|
||||
deliverable_security.safe_equals(other.deliverable_security) &&
|
||||
roll_schedule_expiration.safe_equals(other.roll_schedule_expiration) &&
|
||||
roll_target.Equals(other.roll_target) &&
|
||||
riskless_rate.Equals(other.riskless_rate) &&
|
||||
settlement_price.Equals(other.settlement_price) &&
|
||||
delta_beta.Equals(other.delta_beta) &&
|
||||
vega_beta.Equals(other.vega_beta);
|
||||
|
||||
rv.DeliverableSecurityType = deliverable_security.security_type;
|
||||
rv.DeliverableSymbol = deliverable_security.symbol;
|
||||
rv.DeliverableExpiration = to_exp(deliverable_security.expiration);
|
||||
rv.DeliverableExchange = deliverable_security.exchange;
|
||||
public override bool Equals(object? obj) =>
|
||||
Equals(obj as AnalyticsExpirationParameters);
|
||||
|
||||
rv.RollScheduleSecurityType = roll_schedule_expiration.security_type;
|
||||
rv.RollScheduleSymbol = roll_schedule_expiration.symbol;
|
||||
rv.RollScheduleExpiration = to_exp(roll_schedule_expiration.expiration);
|
||||
rv.RollScheduleExchange = roll_schedule_expiration.exchange;
|
||||
|
||||
rv.RollTarget = roll_target;
|
||||
rv.RisklessRate = riskless_rate;
|
||||
rv.SettlementPrice = settlement_price;
|
||||
rv.DeltaBeta = delta_beta;
|
||||
rv.VegaBeta = vega_beta;
|
||||
return rv;
|
||||
}
|
||||
|
||||
public bool Equals(AnalyticsExpirationParameters other) {
|
||||
return other != null &&
|
||||
security.Equals(other.security) &&
|
||||
_null_equal(driver_security, other.driver_security) &&
|
||||
_null_equal(deliverable_security, other.deliverable_security) &&
|
||||
_null_equal(roll_schedule_expiration, other.roll_schedule_expiration) &&
|
||||
roll_target.Equals(other.roll_target) &&
|
||||
riskless_rate.Equals(other.riskless_rate) &&
|
||||
settlement_price.Equals(other.settlement_price) &&
|
||||
delta_beta.Equals(other.delta_beta) &&
|
||||
vega_beta.Equals(other.vega_beta);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
return Equals(obj as AnalyticsExpirationParameters);
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return security.GetHashCode(); }
|
||||
|
||||
private static bool _null_equal(SecurityExpiration a, SecurityExpiration b) {
|
||||
a = a == null ? null : (a.is_empty() ? null : a);
|
||||
b = b == null ? null : (b.is_empty() ? null : b);
|
||||
return (a == null && b == null) || (a != null && b != null && a.Equals(b));
|
||||
}
|
||||
public override int GetHashCode() =>
|
||||
security.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace mbts.analytics {
|
||||
}
|
||||
|
||||
public IDictionary<mbts.SecurityTuple, double> get_cpp_map() {
|
||||
return input.get_cpp_list().ToDictionary(i => new mbts.SecurityTuple(i.Item1, i.Item2, Venue.Unset), i => i.Item3);
|
||||
return input.get_cpp_list().ToDictionaryCrushed(i => new mbts.SecurityTuple(i.Item1, i.Item2, Venue.Sim), i => i.Item3);
|
||||
}
|
||||
|
||||
private static mbts.SecurityExpiration _unset = mbts.SecurityExpiration.empty;
|
||||
@@ -59,4 +59,4 @@ namespace mbts.analytics {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,13 +51,12 @@ namespace mbts.analytics {
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<Tuple<SecurityType, string, double>> get_cpp_list() {
|
||||
List<Tuple<SecurityType, string, double>> rv = new List<Tuple<SecurityType, string, double>>();
|
||||
public IEnumerable<Tuple<SecurityType, string, double>> get_cpp_list() =>
|
||||
// TODO, cpp
|
||||
return
|
||||
exp_input_map.ToList().Select(kv =>
|
||||
new Tuple<SecurityType, string, double>(kv.Key.security_type, kv.Key.symbol, 1));
|
||||
}
|
||||
exp_input_map
|
||||
.Select(kv => Tuple.Create(kv.Key.security_type, kv.Key.symbol, 1.0))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
public IDictionary<mbts.SecurityTuple, double> get_cpp_map() {
|
||||
return get_cpp_list().ToDictionary(
|
||||
@@ -68,4 +67,4 @@ namespace mbts.analytics {
|
||||
return exp_input_map.Where(kv => filter(kv.Key)).ToDictionary(kv => kv.Key, kv => kv.Value.roll_target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,13 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using bts.api.analytics;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using Spark.Core.Protobuf;
|
||||
|
||||
namespace mbts.analytics
|
||||
{
|
||||
[TestFixture]
|
||||
@@ -21,16 +26,16 @@ namespace mbts.analytics
|
||||
VolSurfaceGreeks.Gamma,
|
||||
VolSurfaceGreeks.Vol,
|
||||
VolSurfaceGreeks.AdjustedVega,
|
||||
VolSurfaceGreeks.OEV,
|
||||
VolSurfaceGreeks.Oev,
|
||||
VolSurfaceGreeks.Theta,
|
||||
VolSurfaceGreeks.DPriceDRiskReversal,
|
||||
VolSurfaceGreeks.DpriceDriskReversal,
|
||||
VolSurfaceGreeks.Vanna,
|
||||
VolSurfaceGreeks.BSMVega,
|
||||
VolSurfaceGreeks.Bsmvega,
|
||||
VolSurfaceGreeks.Moneyness,
|
||||
};
|
||||
|
||||
Theos t = new Theos();
|
||||
VolSurfaceUtilityFunctions.serialize_proto(t);
|
||||
ProtobufSerializationHelper.serialize(t);
|
||||
|
||||
VolSurfaceTimer timer = new VolSurfaceTimer ();
|
||||
List<VolSurfaceStrikeTheo> all_theos = new List<VolSurfaceStrikeTheo>();
|
||||
@@ -65,7 +70,7 @@ namespace mbts.analytics
|
||||
{
|
||||
Console.WriteLine("\nStrikes {0} Handles {1} Total {2}", n_exps * 1.0 * (strike_end - strike_beg) / strike_inc, n_handles, n_handles * n_exps * 1.0 * (strike_end - strike_beg) / strike_inc);
|
||||
byte[] uncomp, comp;
|
||||
timer.start (); uncomp = VolSurfaceUtilityFunctions.serialize_proto(sym_theos); timer.stop();
|
||||
timer.start (); uncomp = ProtobufSerializationHelper.serialize(sym_theos); timer.stop();
|
||||
Console.WriteLine("Serialization time {0}", timer.last_interval_time_ms);
|
||||
timer.start(); comp = VolSurfaceUtilityFunctions.compress(uncomp); timer.stop();
|
||||
Console.WriteLine("Compression time {0}", timer.last_interval_time_ms);
|
||||
@@ -122,4 +127,4 @@ namespace mbts.analytics
|
||||
Console.WriteLine(String.Format("Min time {0} Max time {1} Median time {2} msecs", times.First(), times.Last(), times[times.Count / 2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Spark {
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
static class ConsoleInterop {
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern IntPtr GetConsoleWindow();
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern bool ShowWindow(IntPtr h_wnd, int n_cmd_show);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern int FreeConsole();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#nullable enable
|
||||
namespace mbts.ui {
|
||||
interface ITemplateSelectorKey {
|
||||
string key { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#nullable enable
|
||||
namespace mbts.ui {
|
||||
using bts.collections;
|
||||
|
||||
using System.Collections;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Markup;
|
||||
|
||||
[ContentProperty(nameof(Map))]
|
||||
class KeyedTemplateSelector : DataTemplateSelector {
|
||||
readonly KeyedCollection<TemplateSelectorKeyValue, object?> _map = new(kv => kv.Key);
|
||||
|
||||
public IList Map => _map;
|
||||
public DataTemplate? Default { get; set; }
|
||||
public bool TryMatchType { get; set; }
|
||||
|
||||
public override DataTemplate? SelectTemplate(object? item, DependencyObject container) {
|
||||
if (item is null) {
|
||||
return Default;
|
||||
}
|
||||
var k = _get_key(item);
|
||||
return k is not null && _map.TryGetValue(k, out var result) ?
|
||||
result.Value : Default;
|
||||
}
|
||||
|
||||
object? _get_key(object? item) {
|
||||
if (item is null) {
|
||||
return null;
|
||||
}
|
||||
var key = item;
|
||||
if (key is ITemplateSelectorKey tsk) {
|
||||
key = tsk.key;
|
||||
}
|
||||
if (key is null && TryMatchType) {
|
||||
key = item.GetType();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#nullable enable
|
||||
namespace mbts.ui {
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
|
||||
[ContentProperty(nameof(Value))]
|
||||
class TemplateSelectorKeyValue {
|
||||
public object? Key { get; set; }
|
||||
public DataTemplate? Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
using bts.api;
|
||||
|
||||
using mbts;
|
||||
using mbts.config;
|
||||
using mbts.spark;
|
||||
using mbts.ui;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Composition;
|
||||
using System.Diagnostics;
|
||||
|
||||
@@ -8,30 +8,38 @@ using mbts.ui;
|
||||
using mbts.ui.spark;
|
||||
using mbts.ui.utilities;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Composition;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows;
|
||||
using bts.api.analytics;
|
||||
|
||||
using Disposable = mbts.Disposable;
|
||||
using BCG;
|
||||
|
||||
namespace bts {
|
||||
[Export(typeof(IShellDaemon))]
|
||||
class AnalyticsDaemon : IShellDaemon, IDisposable {
|
||||
private readonly IBus _bus;
|
||||
private readonly AnalyticsService _analytics_service;
|
||||
private readonly bts.api.orderman.OrderService _order_service;
|
||||
private readonly VolSurfaceBusManager _vs_manager;
|
||||
private readonly SpreadManager _spread_manager;
|
||||
private readonly SpreadCalculationSynchronizer _spread_calc;
|
||||
|
||||
IDisposable _dispose;
|
||||
|
||||
[ImportingConstructor]
|
||||
public AnalyticsDaemon(IBus bus, AnalyticsService analytics_service) {
|
||||
public AnalyticsDaemon(IBus bus, AnalyticsService analytics_service,
|
||||
bts.api.orderman.OrderService order_service) {
|
||||
bts.Log.Gen.info("AnalyticsDaemon started");
|
||||
_bus = bus;
|
||||
_analytics_service = analytics_service;
|
||||
_vs_manager = new VolSurfaceBusManager(_bus, _analytics_service);
|
||||
_order_service = order_service;
|
||||
_vs_manager = new VolSurfaceBusManager(_bus, _analytics_service, _order_service);
|
||||
_spread_manager = new SpreadManager(_vs_manager.bb(), "xxx");
|
||||
_spread_calc = new SpreadCalculationSynchronizer(_vs_manager.bb());
|
||||
}
|
||||
|
||||
public void Dispose() =>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using bts.api;
|
||||
using bts.spark;
|
||||
|
||||
using mbts;
|
||||
using mbts.spark;
|
||||
using mbts.ui;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
@@ -46,7 +47,7 @@ namespace bts {
|
||||
return;
|
||||
}
|
||||
log.info($"received request to delete the following {keys.Count} securities: {string.Join(", ", keys)}");
|
||||
var (orders, orders_success) = await _orders_model.security_order_groups.FirstAsyncTask(SparkUtils.DefaultTimeOut);
|
||||
var (orders, orders_success) = await _orders_model.security_orders.FirstAsyncTask(SparkUtils.DefaultTimeOut);
|
||||
if (!orders_success) {
|
||||
var msg = "Unable to delete synthetic securities: " +
|
||||
$"timed out waiting for orders table (must verify that a synthetic security does not have any working orders before it can be deleted).";
|
||||
|
||||
@@ -7,6 +7,8 @@ using mbts;
|
||||
using mbts.spark;
|
||||
using mbts.ui;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Composition;
|
||||
|
||||
@@ -11,6 +11,7 @@ using System.Reactive.Linq;
|
||||
|
||||
using SecurityKey = System.UInt32;
|
||||
using MDHandle = mbts.co2.FakeMDConsumerHandle;
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
namespace bts {
|
||||
//[Export(typeof(IShellDaemon))]
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
#nullable enable
|
||||
namespace bts.daemons {
|
||||
using bts.api;
|
||||
using bts.utils;
|
||||
|
||||
using mbts;
|
||||
using mbts.spark;
|
||||
using mbts.ui;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Composition;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
|
||||
[Export(typeof(IShellDaemon))]
|
||||
public sealed class FakeSymbolDriverDaemon : IShellDaemon, IDisposable {
|
||||
IDisposable? _dispose;
|
||||
|
||||
public FakeSymbolDriverDaemon(IBus bus) {
|
||||
int tid_counter = 1;
|
||||
IDictionary<int, string> vol_surfaces = new Dictionary<int, string>();
|
||||
var sec_trades = new Dictionary<uint, List<ITradeLogRow>>();
|
||||
_dispose = Disposable.Create(
|
||||
bus.subscribe(SparkTags.VolSurfaceListTag).Subscribe(vss => vol_surfaces = vss),
|
||||
bus.subscribe(SparkTags.SecuritiesTag).SubscribeEach(secs => {
|
||||
var btc_secs = secs.Values.Where(
|
||||
s => s.security.Symbol == "BTC" &&
|
||||
s.security.ContractCase == Security.ContractOneofCase.Future)
|
||||
.ToList();
|
||||
var fake_trades = btc_secs.Select(
|
||||
s => get_fake_trade(to_sec_exp(s.security), 4200)).ToList();
|
||||
bus.post(SparkTags.TradeLogTag, fake_trades);
|
||||
var bbo_upd_refs = btc_secs.ToDictionary(s => s.security.Id, _ => 0UL);
|
||||
var driver_sym_prices = btc_secs.ToImmutableDictionary(
|
||||
s => to_sec_exp(s.security), get_driver_price);
|
||||
|
||||
double get_driver_price(SecurityMD smd) {
|
||||
var upd_ref = bbo_upd_refs[smd.security.Id];
|
||||
var rv = double.NaN;
|
||||
if (smd.md.get_bbo(ref upd_ref, out var bid, out var ask)) {
|
||||
rv = bid.price.if_nan(ask.price);
|
||||
}
|
||||
bbo_upd_refs[smd.security.Id] = upd_ref;
|
||||
return rv;
|
||||
}
|
||||
|
||||
return Observable.Interval(TimeSpan.FromSeconds(2)).Subscribe(_ => {
|
||||
var bd = driver_sym_prices.ToBuilder();
|
||||
foreach (var sec in btc_secs) {
|
||||
var sec_exp = to_sec_exp(sec.security);
|
||||
bd[sec_exp] = get_driver_price(sec).if_nan(driver_sym_prices[sec_exp]);
|
||||
}
|
||||
driver_sym_prices = bd.ToImmutable();
|
||||
foreach (var vsid in vol_surfaces.Keys) {
|
||||
bus.post(SparkTags.VolSurfaceDriverSymbolPriceTag(vsid), driver_sym_prices);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
static SecurityExpiration to_sec_exp(SecurityImmutable sec) =>
|
||||
new(sec.Exchange, sec.ContractCase, sec.Symbol, sec.security_expiration() ?? DateTime.MinValue, sec.Id);
|
||||
|
||||
ITradeLogRow get_fake_trade(
|
||||
SecurityExpiration sec_exp,
|
||||
double price,
|
||||
int size = 1,
|
||||
string account = "ACC A",
|
||||
uint account_id = 1,
|
||||
double? strike = null,
|
||||
PutOrCall? cp = null,
|
||||
double? theo = null
|
||||
) {
|
||||
var t1 = new FakeTradeLogRow(
|
||||
Interlocked.Increment(ref tid_counter),
|
||||
sec_exp,
|
||||
strike,
|
||||
cp,
|
||||
size,
|
||||
price,
|
||||
theo ?? price + 10 * new Random().NextDouble(),
|
||||
account,
|
||||
account_id,
|
||||
true,
|
||||
DateTime.Now,
|
||||
"FakeTrader",
|
||||
1);
|
||||
return t1;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() =>
|
||||
Disposable.dispose(ref _dispose);
|
||||
}
|
||||
}
|
||||
Loaded 100 of 1591 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user