Compare commits

...
560 Commits
Author SHA1 Message Date
Taha Afzal 843f42c3e3 Merge branch 'trade_analysis' of bitbucket.org:bluetradesys/spark into trade_analysis 2020-04-06 16:00:24 -04:00
Taha Afzal 3afc3d64b6 changed the keys 2020-04-06 16:00:12 -04:00
pfisher 44f2cdd7c0 change aws keys 2020-03-31 11:00:26 -05:00
Taha Afzal 3f36f54781 Added TopBooks to ProcessedBook 2020-03-03 17:09:56 -05:00
Taha Afzal 59e66cf1ef Sniper reads from multiple files recursively 2020-03-02 18:32:19 -05:00
Taha Afzal dec178f133 ignoring all trades that are not making sense 2020-03-02 09:46:10 -05:00
Taha Afzal e9c9a3bad6 Function to get orders for both sides of the trade 2020-03-02 09:46:10 -05:00
Taha Afzal 46a4aa99df Added quote order marketat the time the quote order was updated 2020-03-02 09:46:10 -05:00
Taha Afzal 1097bbcd60 Q leg display 2020-03-02 09:46:10 -05:00
Taha Afzal 840ba7e0b3 Added total qty and no of orders 2020-03-02 09:46:10 -05:00
Taha Afzal 7e7e88cedc Proximity search bug 2020-03-02 09:46:10 -05:00
Taha Afzal 727a3d5b97 Cleaning up some mess 2020-03-02 09:46:10 -05:00
Taha Afzal 3044d5d5ec Bin searching for trades 2020-03-02 09:46:10 -05:00
Taha Afzal 506084242a Refinement of orders/trades 2020-03-02 09:46:10 -05:00
Taha Afzal 067946127a cleaning up 2020-03-02 09:46:10 -05:00
Taha Afzal 297848bcdb Re-org of passive quote detection 2020-03-02 09:46:10 -05:00
Pedro Pinto 376d64cfbe updated db script to incorporate timestamps 2020-02-06 10:07:14 -05:00
Pedro Pinto bdf3ae7c92 Added unix timestamps to csvs 2020-02-06 09:22:22 -05:00
Pedro Pinto 97d0637d88 Updated tools 2020-02-04 09:27:19 -05:00
Pedro Pinto b4d85cdadf Merge branch 'trade_analysis' of bitbucket.org:bluetradesys/spark into trade_analysis 2020-02-04 09:24:40 -05:00
Pedro Pinto 2b0cb84069 Changed synchronization script to default to synching yesterday 2020-02-04 09:23:25 -05:00
Pedro Pinto 0412c45ed3 Removed build step 2020-02-03 15:48:20 -05:00
Pedro Pinto b984613b8a Non interactive use of postgres 2020-02-03 15:23:21 -05:00
Pedro Pinto e712433d6f More tweaks. 2020-02-03 15:21:27 -05:00
Pedro Pinto 4d8b20d084 Fixed path in postgres sql. 2020-02-03 15:14:08 -05:00
Pedro Pinto df86187457 Tool tweaks 2020-02-03 14:56:01 -05:00
Pedro Pinto 620ea4b4af Tweaked date tool 2020-02-03 13:56:21 -05:00
Pedro Pinto e2951b4436 Added pgadmin tool 2020-02-03 10:12:32 -05:00
Pedro Pinto 0ebc3cf111 Fixed a few issue with analysis tools 2020-02-03 09:58:39 -05:00
Pedro Pinto fd9b2990ae Added easier to use tools for analysis 2020-01-31 16:28:18 -05:00
Pedro Pinto 15d24f96c2 Updated externals, private tools 2020-01-31 16:28:18 -05:00
Pedro Pinto b1bbc6ab0d Updated docker 2020-01-31 16:28:17 -05:00
Pedro Pinto 39be9e41c8 Rewound externals because tip is broken 2020-01-31 16:28:17 -05:00
Pedro Pinto fd91b78742 sync/parse/load tools 2020-01-31 16:28:17 -05:00
Pedro Pinto 95a5dd0ceb updated docker 2020-01-31 16:28:17 -05:00
Pedro Pinto a9aa76deed Updated gitignore and externals 2020-01-31 16:28:17 -05:00
Taha Afzal a80a4f327e Fixed theoutput data zero fills 2020-01-31 13:51:52 -05:00
Taha Afzal 7e9a853a50 filtering books 2020-01-31 11:38:11 -05:00
Taha Afzal 0e0d4412b8 Merge branch 'trade_analysis' of bitbucket.org:bluetradesys/spark into trade_analysis 2020-01-30 22:45:06 -05:00
Taha Afzal b3a19eab05 Filtering quote fills for orders 2020-01-30 22:44:42 -05:00
Pedro Pinto fdb1826e01 Added a tool to download cme historical data 2020-01-30 13:27:02 -05:00
Taha Afzal e2d6bc1c45 Order parsing 2020-01-29 19:43:36 -05:00
Taha Afzal d5a06cc3e7 circle filling in 2020-01-27 22:58:22 -05:00
Taha Afzal 3e7c2e3c18 circle analysis 2020-01-22 11:50:49 -05:00
Taha Afzal ea6eaf6e1d contracts show in entry:exit 2020-01-21 10:40:11 -05:00
Taha Afzal dea2358c51 cleaned up some wrappers to simplify the code 2020-01-17 18:43:08 -05:00
Taha Afzal 491d0c0b7a no exponent mapping 2020-01-17 11:50:06 -05:00
Taha Afzal f593b457a5 Market close times factored in 2020-01-17 11:25:26 -05:00
Taha Afzal 10a3ba52f4 Added max processing time 2020-01-16 11:03:27 -05:00
Taha Afzal 56bc7f216a Parallelized the sniper analysis across file (in batches) 2020-01-15 22:11:04 -05:00
Taha Afzal a57b99b2e8 BEtter formatting of output 2020-01-14 14:49:40 -05:00
Taha Afzal d3a0595934 Cleaning 2020-01-14 10:54:55 -05:00
Taha Afzal a659fbc7cd Sniper analysis works on multiple files now 2020-01-14 09:32:08 -05:00
Taha Afzal 542b8e946d mass sniper analysis 2020-01-13 11:16:06 -05:00
Taha Afzal d4d1f8f533 download args changed 2020-01-12 18:18:56 -05:00
Taha Afzal 624a432c44 ignoring ticks from when the market is closed 2020-01-12 13:13:05 -05:00
Pedro Pinto 68f09c2e27 Fixed crash when the timen take to parse was rounded to 0 secs. 2020-01-11 18:45:36 -05:00
Taha Afzal 3d22a58bac ParseHistoricalFIX takes a path and processes all files with name _raw in it 2020-01-10 19:19:52 -05:00
Taha Afzal 33e46b2fb1 Batch download 2020-01-10 11:14:25 -05:00
Taha Afzal cb357440ed cleaned up some old code 2020-01-09 14:12:04 -05:00
Taha Afzal a88670b95d Added headers to the output 2020-01-09 13:22:39 -05:00
Taha Afzal bb70db70b5 Better output generation 2020-01-09 11:28:41 -05:00
Taha Afzal 2c3e4b7d4d loading and validating 2020-01-06 20:04:45 -05:00
Taha Afzal 843c4f447f Merge branch 'trade_analysis' of bitbucket.org:bluetradesys/spark into trade_analysis 2020-01-03 17:07:26 -05:00
Taha Afzal d41c76e6a3 validatio 2020-01-03 17:06:55 -05:00
Pedro Pinto 805722cdc7 Fixed the calculation of the book in the historical data parser. 2020-01-03 16:07:32 -05:00
Pedro Pinto ef64d3c25e Fixed weird auto&& in HandleIndex.h 2020-01-03 12:27:52 -05:00
Pedro Pinto 0b0cf744a6 Added more information to parser 2020-01-03 12:22:44 -05:00
Pedro Pinto c3410db0aa Fixed clang build. 2020-01-03 12:22:44 -05:00
Eric Harding c5a89b0bb6 fix a couple clang warnings 2020-01-03 11:45:44 -05:00
Taha Afzal 89f5f94588 validation 2020-01-02 19:39:50 -05:00
Taha Afzal c8ac56b0a1 Merge branch 'trade_analysis' of bitbucket.org:bluetradesys/spark into trade_analysis 2020-01-02 19:33:15 -05:00
Pedro Pinto b152b2b853 Added a parser of historical MD to facilitate analysis. 2020-01-02 14:01:57 -05:00
Pedro Pinto 354390ed11 Fixed clang build. 2020-01-02 14:01:48 -05:00
Taha Afzal 08839aadb2 book validation code 2020-01-01 22:03:23 -05:00
Taha Afzal b7cb17500c Downloading new book data 2019-12-31 18:32:45 -05:00
Taha Afzal 01b50e1138 Added function skeleton to compure possible fills 2019-12-30 19:33:04 -05:00
Taha Afzal 8fdb7485ba new order and trade protos 2019-12-30 19:22:40 -05:00
Taha Afzal 293d51038f Circle spreads initial analysis 2019-12-27 18:55:54 -05:00
Taha Afzal 8db81fa248 countering for the trades and orders files 2019-12-27 10:27:18 -05:00
Taha Afzal 47628089ac Recording trades and orders 2019-12-26 21:08:49 -05:00
Taha Afzal 8b2c5a60aa Added NG exp 2019-12-24 12:41:35 -05:00
Taha Afzal f1df673e61 spread parsing gix, Z29 showed up 2019-12-23 18:43:14 -05:00
Taha Afzal 9faee77360 merging vwap 2019-12-23 16:38:58 -05:00
Kevin Darby 0fd45ba92a . 2019-12-23 00:15:10 -05:00
Kevin Darby 4e440fc218 debugging KFillModel 2019-12-22 16:46:06 -05:00
Kevin Darby 41c8351709 ready to test KFillModel 2019-12-22 15:14:38 -05:00
Kevin Darby 1238648c2b leveling applies to those orders that did not receive prorata 2019-12-20 23:43:34 -05:00
Kevin Darby 03ac88683f KFillModel looks to be code complete, needs debug / test 2019-12-20 23:37:39 -05:00
Kevin Darby fe4c057b20 working on KFillModel 2019-12-20 18:18:40 -05:00
Kevin Darby e6c6997e46 prorata start 2019-12-19 23:47:41 -05:00
Kevin Darby ddd8778bab added some comments for taha, some display stuff for notebook 2019-12-19 18:09:02 -05:00
Kevin Darby f95d258210 put real life data with notebooks 2019-12-19 17:13:00 -05:00
Kevin Darby a2e1cf8dd5 moving code around 2019-12-19 15:54:37 -05:00
Kevin Darby 0b8b68e6e6 Merge branch 'csv_export' of bitbucket.org:bluetradesys/spark into vwap 2019-12-19 14:48:38 -05:00
Kevin Darby 8658a11d1f 100 ticks in one day...not enough 2019-12-19 11:20:58 -05:00
Kevin Darby d0aa90131a top doesn't do much 2019-12-19 00:35:11 -05:00
Kevin Darby ffb30177b1 trying top 2019-12-19 00:24:57 -05:00
Kevin Darby 297093f9ce honing in 2019-12-18 23:41:31 -05:00
Kevin Darby 5ba8440877 couple small bugs and some diagnostics 2019-12-18 22:35:35 -05:00
Kevin Darby 228e49d152 taking this home 2019-12-18 18:28:39 -05:00
Kevin Darby a9e983a717 we rollin 2019-12-18 15:32:19 -05:00
Jake Norbut 25445d58d0 refactoring TaS CSV export 2019-12-18 13:48:14 -06:00
Jake Norbut 0b313a8aa8 refactoring Fills CSV export 2019-12-18 13:47:36 -06:00
Jake Norbut 54f954fd4b adding CSV export to order book 2019-12-18 13:47:03 -06:00
Jake Norbut 980f38ba03 using OrderedDictionary to CSVs are output with a predictable column order 2019-12-18 13:46:22 -06:00
Kevin Darby 198086e639 got roll going 2019-12-18 13:16:49 -05:00
Jake Norbut 9eada2724b Having the Command be on the Window rather than the VM; nice thinking John 2019-12-18 10:11:10 -06:00
Jake Norbut b5f53ee918 adding csv_properties to TimeAndSalesVM.Row 2019-12-18 10:10:04 -06:00
Kevin Darby a3a8eb14ad trying another way 2019-12-18 00:07:34 -05:00
Kevin Darby 333acf0822 progress 2019-12-17 18:17:45 -05:00
Jake Norbut efc175f654 adding export to csv command to Fills window 2019-12-17 10:32:58 -06:00
Jake Norbut 6074afd999 adding csv export command to fills vm 2019-12-17 10:32:15 -06:00
Jake Norbut 219dff4055 adding new export_csv IDialogCommand which just creates a new file 2019-12-17 10:28:57 -06:00
Jake Norbut 9a3b07b622 adding ToCsv IEnumerable ext method in a new util namespace 2019-12-17 10:21:38 -06:00
Kevin Darby 1af49376b6 progress in passive fills model 2019-12-16 23:42:58 -05:00
Kevin Darby f90f6cfb33 using sortedlist for our orders in fifo 2019-12-16 23:27:29 -05:00
Kevin Darby 6433f9ba98 Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-12-16 21:39:53 -05:00
Kevin Darby cc1882ea1a trying to add iceberg reup to passive fill stream 2019-12-16 18:46:30 -05:00
Kevin Darby 56e83a1e69 fix timestamp bug 2019-12-16 15:17:59 -05:00
Eric Harding 2688281a10 Protect against ICE 0-leg spread data on cert 2019-12-16 10:26:34 -05:00
Kevin Darby 69d429fa4e nb 2019-12-15 23:08:36 -05:00
Kevin Darby e8c9e70a4a change name of methods 2019-12-15 21:30:22 -05:00
Kevin Darby 6c78850902 need to deduct from our orders in fifo model 2019-12-15 14:24:14 -05:00
Kevin Darby adab377e44 got some passive fills, need to verify 2019-12-13 23:09:31 -05:00
Kevin Darby 7bdaa35768 passive fifo fill model 2019-12-13 22:14:02 -05:00
Kevin Darby 1c7f79f293 icomparer 2019-12-13 18:18:47 -05:00
Kevin Darby 3a7246c5b0 time to leave 2019-12-13 18:16:59 -05:00
Taha Afzal 17a1190e34 added exponents for HE,ZC 2019-12-13 18:16:13 -05:00
Kevin Darby 3bd95de839 bugs 2019-12-13 18:14:23 -05:00
Kevin Darby 576d3836b3 fills by query 2019-12-13 18:05:41 -05:00
Kevin Darby f1788b172c trying to layer these as queries 2019-12-13 16:53:56 -05:00
Taha Afzal 82834dc9e6 Parallelized the processing of file for sniper 2019-12-13 14:46:30 -05:00
Kevin Darby ae5912d41d now we're cookin 2019-12-13 14:36:15 -05:00
Kevin Darby adbab4057f renames 2019-12-13 14:15:29 -05:00
Kevin Darby ca4a639b86 changed IFillModel to IMatchingModel, because that's really what it is, now I need fill model 2019-12-13 14:12:55 -05:00
Kevin Darby a539a06f45 interim push to go more stateless 2019-12-13 13:33:18 -05:00
Taha Afzal 2ff96e3528 more helper functions 2019-12-13 12:37:17 -05:00
Kevin Darby 1a87544ccb orders 2019-12-12 23:51:18 -05:00
Kevin Darby b97450297e update notes 2019-12-12 23:10:07 -05:00
Kevin Darby 6a1040a339 regen for trade counter parties 2019-12-12 23:07:49 -05:00
Kevin Darby 7fe20129d2 seems like we really can't count on the order of trade vs delete, so we have to use the price book to approximate crosses 2019-12-12 22:46:12 -05:00
Kevin Darby 4f59c1bb47 1 based arrays, so good 2019-12-12 18:26:10 -05:00
Kevin Darby 3ba17f1c87 allow disk in query 2019-12-12 18:19:08 -05:00
Kevin Darby ef874dda7e bigblue is slow, but I think we're on the right track now 2019-12-12 18:10:03 -05:00
Kevin Darby 6e966a6229 write the data with orders in same mongo document 2019-12-12 16:56:43 -05:00
Kevin Darby ed3b890c67 might have to store the data a little differently 2019-12-12 15:16:02 -05:00
Kevin Darby 2a46fd6227 push for pete 2019-12-12 14:27:28 -05:00
Taha Afzal 74f1bf2480 functions to remove duplicates 2019-12-12 11:35:19 -05:00
Kevin Darby 23e13846c6 botched order priority when only reducing size 2019-12-12 10:13:40 -05:00
Kevin Darby 39e4549972 only got one fill 2019-12-11 22:55:12 -05:00
Kevin Darby d924962546 kinda starting to work 2019-12-11 18:11:13 -05:00
Kevin Darby 0f1c81eb48 roundtrip 2019-12-11 18:07:33 -05:00
Kevin Darby 5e6fe7282d moved code around verified roll_snipe still works 2019-12-11 17:02:47 -05:00
Taha Afzal 4e48bcf6b5 refactoring 2019-12-11 13:33:07 -05:00
Kevin Darby a47dad1ce4 changes in algo backtester to facilitate jupyter, will probably remove backwards compatibility in a bit 2019-12-11 13:28:48 -05:00
Taha Afzal 6fd829df49 Silly bug that was overwriting the lined up markets 2019-12-11 11:49:30 -05:00
Kevin Darby 1809c778e2 ialgo 2019-12-10 23:40:55 -05:00
Kevin Darby 2178e16d3c restructure for jupyter 2019-12-10 22:50:49 -05:00
Kevin Darby deadbc6cf2 we actually do want one row per order for better query perf 2019-12-10 21:14:57 -05:00
Kevin Darby 445d77223f move some stuff around 2019-12-10 18:18:05 -05:00
Kevin Darby 09b24e33fc Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-12-09 14:05:56 -06:00
Kevin Darby 84553d11c4 new_externals 2019-12-09 14:05:04 -06:00
Kevin Darby eb1bab5878 linux build 2019-12-09 14:18:05 -05:00
Kevin Darby a7a58038b3 release build 2019-12-09 14:15:04 -05:00
Kevin Darby 1b9af8f010 new externals 2019-12-09 11:45:10 -05:00
Kevin Darby 113c4fe539 changes in notebooks, I am matching Taha 2019-12-09 11:12:06 -05:00
Kevin Darby c33662dc2c py 2019-12-09 00:30:36 -05:00
Taha Afzal 0dcb3d3dfd Added microscope for a closer look! 2019-12-08 21:53:39 -05:00
Kevin Darby 8817b22376 write book with trades 2019-12-08 14:37:48 -05:00
Taha Afzal 212f2a3d36 can run the sniper on one synthetic only, too 2019-12-08 10:39:04 -05:00
Kevin Darby b48da514e5 I think we got it 2019-12-08 00:18:25 -05:00
Taha Afzal 649225ef6c unifying the spread calc function 2019-12-07 22:55:18 -05:00
Kevin Darby 59cba2456b honing in on some timing issue 2019-12-07 22:02:45 -05:00
Kevin Darby 839c3d430b fixed build 2019-12-07 16:27:30 -05:00
Taha Afzal 35495dc7cf better formatting 2019-12-06 20:17:14 -05:00
Kevin Darby 5b1f2522e1 found bug in synth processor, won't build until I fix 2019-12-06 18:29:58 -05:00
Taha Afzal 8ee78c83d2 writes result to a file: 2019-12-06 18:19:29 -05:00
Kevin Darby 6c3ccdf856 that's 400 micros, not nanos 2019-12-06 14:30:15 -05:00
Kevin Darby 157d834cbb getting somewhere with the roll 2019-12-06 13:42:40 -05:00
Taha Afzal b4beb7c0db moved BookEntry and TimeRange into protos 2019-12-06 13:19:03 -05:00
Kevin Darby 4f2e9b19cc trying to merge some collections 2019-12-05 23:49:11 -05:00
Kevin Darby fed7ca1ff3 honing in 2019-12-05 18:20:28 -05:00
Taha Afzal f84517c15c cleaning up some mes 2019-12-05 17:32:05 -05:00
Taha Afzal 075354a975 Sniper analysis works on generated spreaders 2019-12-05 11:08:45 -05:00
Kevin Darby 73cfa17791 notes 2019-12-05 10:50:54 -05:00
Kevin Darby 474a53ba92 change notebook destination to big blue 2019-12-05 10:50:10 -05:00
Kevin Darby 69612eaee7 thought better of two tables, this makes simulation way easier 2019-12-04 23:33:48 -05:00
Kevin Darby b7ad777de4 have to go back to orders stream 2019-12-04 22:44:22 -05:00
Kevin Darby d6a70d852e added orders to the mongo 2019-12-04 18:10:47 -05:00
Taha Afzal 4450476a40 simplified lining up of books 2019-12-04 09:49:26 -05:00
Kevin Darby 33f12edce5 finally figured out timestamps 2019-12-03 23:47:48 -05:00
Kevin Darby ab2e9fe6bd I might have fixed the dates 2019-12-03 22:34:04 -05:00
Kevin Darby 8bcffea686 jupyter 2019-12-03 18:17:31 -05:00
Kevin Darby 941472c5c0 bug in spread processing, small things in simulation 2019-12-02 23:35:42 -05:00
Kevin Darby d2a5e03976 notes 2019-12-02 18:14:54 -05:00
Kevin Darby 97e3bce327 moving historical analysis stuff to spark_historical 2019-12-02 16:06:05 -05:00
Kevin Darby e766667584 <= vs < 2019-12-02 14:48:54 -05:00
Kevin Darby a93c110c29 better serialization for pbuf Timestamps 2019-12-02 14:43:29 -05:00
Taha Afzal 3b0bbe6908 simplified 2019-12-02 13:09:11 -05:00
Taha Afzal 1147edcbb9 tests 2019-12-02 12:44:10 -05:00
Kevin Darby e1c7b89408 mongo 2019-12-01 21:38:55 -05:00
Taha Afzal c50133ba02 tests 2019-12-01 16:17:14 -05:00
Taha Afzal f1dbacb989 forcing an exponent to fix the prices 2019-11-29 16:43:21 -05:00
Kevin Darby ad3ce72a39 added a mongo generator, much nicer 2019-11-29 16:35:46 -05:00
Kevin Darby 57f48472d3 trying out timescaledb, 2019-11-29 15:47:20 -05:00
Taha Afzal 0535eedbbf merging 2019-11-29 15:34:44 -05:00
Kevin Darby 45ae6ac585 parsing this data needs to get faster 2019-11-29 13:33:06 -05:00
Taha Afzal 2740de913c BookState is now called BookSeries 2019-11-29 09:47:46 -05:00
Kevin Darby 5a90676a25 need a finally 2019-11-27 21:57:03 -05:00
Kevin Darby 8536f782ce Merge branch 'dotnet' of bitbucket.org:bluetradesys/spark into vwap 2019-11-27 21:47:03 -05:00
Kevin Darby 5f45ddf210 wack vs backwack 2019-11-28 02:46:27 +00:00
Kevin Darby 67c83c7d68 remove postgres tag from spark_vm_shell 2019-11-27 21:10:22 -05:00
Kevin Darby 6f6e1a9e55 Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-11-27 21:01:43 -05:00
Kevin Darby c80451bc5e added async 2019-11-27 18:20:14 -05:00
Taha Afzal ba53543e43 Parsing the sniper input file correctly 2019-11-27 18:07:59 -05:00
Kevin Darby d6a533ca5c PR feedback 2019-11-27 17:21:24 -05:00
Kevin Darby e0112eff89 stuff 2019-11-27 17:20:55 -05:00
Kevin Darby 38b29f0afb more pg 2019-11-27 17:14:29 -05:00
Kevin Darby 8b9d689a5f able to preprocess trades and books into a postgres 2019-11-27 16:18:56 -05:00
Kevin Darby 097edb2726 Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-11-27 15:09:58 -05:00
Kevin Darby 12e3e9a222 gave up and decided to run postgres in docker on my host 2019-11-27 15:08:51 -05:00
Taha Afzal ce19ba1419 added MarketQueriesHelper 2019-11-27 14:04:32 -05:00
Taha Afzal c81a22e55d Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-11-27 11:50:45 -05:00
Taha Afzal bd04f49ff5 Reorg 2019-11-27 11:50:38 -05:00
Eric Harding 3a9e8970d6 merge temp_synthetic_compute 2019-11-27 10:28:22 -05:00
Taha Afzal 9837645d16 Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-11-27 09:34:43 -05:00
Taha Afzal 1789c02295 skeleton in place 2019-11-27 09:34:28 -05:00
Kevin Darby 3280376df3 Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-11-26 21:31:42 -05:00
Taha Afzal d251593f04 parsing sniper args 2019-11-26 19:49:51 -05:00
Kevin Darby 9afeb29c63 pg 2019-11-26 18:21:06 -05:00
Kevin Darby e4dc07ce3f Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-11-26 17:40:01 -05:00
Kevin Darby 2bbf22a153 new docker for postges some db code 2019-11-26 16:03:43 -05:00
Taha Afzal a598ae8bd2 Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-11-26 15:40:19 -05:00
Taha Afzal 4d72b9d2e7 filling in 2019-11-26 15:40:10 -05:00
Kevin Darby e000b1d0c0 hmm 2019-11-26 00:07:36 -05:00
Kevin Darby ef4261fe7f small parser tweaks for taha / me 2019-11-25 23:17:30 -05:00
Kevin Darby c3b75aa742 rename packet variable 2019-11-25 15:13:30 -05:00
Taha Afzal 2518be52fb book post processing path formalized 2019-11-25 15:12:29 -05:00
Kevin Darby f3ee6c0e30 TWAP completes 2019-11-25 14:54:15 -05:00
Kevin Darby 94363767ab small bug in slicer 2019-11-25 14:10:54 -05:00
Taha Afzal 9dd6e39665 post processing of books + helper functions to allign boks 2019-11-25 09:34:38 -05:00
Eric Harding b62d9751cf chown duplicates files in docker image 2019-11-20 14:57:56 -05:00
Jake Norbut 26b5fe5699 updating release notes 2019-11-20 09:47:48 -06:00
Jake Norbut 2fccceb91d Merged in ladder_recenter_no_kb (pull request #379)
Ladder recenter no kb
2019-11-20 15:47:09 +00:00
Jake Norbut fa49a0de07 adding new test 2019-11-20 09:45:51 -06:00
Jake Norbut bd28a0fa54 delete old test 2019-11-20 09:45:27 -06:00
Jake Norbut 14ebe5ef51 (shift or alt) + double click to recenter all ladders 2019-11-20 09:14:20 -06:00
Jake Norbut a9b4049307 relocating bus.post of recenter all to common public ladder function 2019-11-20 09:13:58 -06:00
Jake Norbut 234d499731 adding ladder spacebar test 2019-11-19 08:51:38 -06:00
Eric Harding 324b9c1cc7 Merge branch 'prod' of bitbucket.org:bluetradesys/spark 2019-11-19 09:04:33 -05:00
Kevin Darby 722ae68cf1 more 2019-11-18 15:08:09 -05:00
Eric Harding 6aad329e09 Include ice symbol list in defaults for windows 2019-11-18 13:04:00 -05:00
Jake Norbut 0641cf45d9 Merged in SP-261_bye_bye_butterfly (pull request #366)
RTM - no more butterfly defaults

Approved-by: Jake Norbut <jake.norbut@bluetradesys.com>
2019-11-18 16:34:35 +00:00
Jake Norbut 1fe0efe5c3 Merged in SP-264_price_display_format (pull request #374)
RTM - SP-264 drop tick separator in ladder prices

Approved-by: John Colvin <john.colvin@bluetradesys.com>
2019-11-18 16:17:31 +00:00
Jake Norbut 93938b6ef2 fix merge 2019-11-18 10:15:19 -06:00
Jake Norbut 818806a4e1 Merged in SP-263_recenter_on_spacebar (pull request #371)
RTM - SP-263 recenter on spacebar

Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2019-11-18 15:35:59 +00:00
Jake Norbut 261bf3e475 Merged in SP-260_local_max_clip (pull request #370)
RTM SP-260 local max clip

Approved-by: Eric Harding <eric.harding@bluetradesys.com>
2019-11-18 15:34:30 +00:00
John Colvin dbe2194ed3 Merged in SP-265-pnl-cast-exception (pull request #376)
SP-265 pnl cast exception

Approved-by: Jake Norbut <jake.norbut@bluetradesys.com>
2019-11-18 15:26:06 +00:00
Eric Harding e39313ecf6 Add merge_synthetic_book sample test code 2019-11-15 17:42:49 -05:00
Eric Harding 8095100bee p/invoke for synthetic book computation 2019-11-15 16:11:02 -05:00
John Colvin 45e10ca377 SP-265 use 'is' instead of explicit cast to IPNLCellData (the cast should work; this is defensive) 2019-11-14 21:09:31 -06:00
Eric Harding c3299232f1 Update release notes 2019-11-14 17:44:24 -05:00
John Colvin 4de77ce339 pnl sometimes duplicates grouping columns when they are changed in settings dialog 2019-11-14 16:12:58 -06:00
John Colvin 96f71290a4 SP-265 pnl crash due to CastException 2019-11-14 16:12:19 -06:00
Kevin Darby a76415a52f native algo state 2019-11-14 17:04:42 -05:00
Jake Norbut e2b80942df adding manual test 2019-11-14 15:58:59 -06:00
Jake Norbut 51fb068469 adding manual test 2019-11-14 15:51:40 -06:00
Kevin Darby 06305ee4ac having trouble routing fills down to c++ 2019-11-14 16:21:51 -05:00
Eric Harding 81b36edfe3 Merged in subprocess (pull request #375)
[RTM] Simple sparkd subprocess runner
2019-11-14 20:26:38 +00:00
Eric Harding 90976ffeba Merged in init_spark_plugin (pull request #372)
[RTM] Always init_spark_plugin() for libspark.so
2019-11-14 20:24:50 +00:00
Eric Harding 43aad8b53f merge master 2019-11-14 15:24:36 -05:00
Eric Harding 5434647ecb Merged in SP-262-read_latest_crash_dump-crahes (pull request #368)
[RTM] SP-262 check for directory exists in keep_n_matching_files

Approved-by: Jake Norbut <jake.norbut@bluetradesys.com>
2019-11-14 20:22:53 +00:00
Eric Harding 7c4aa11c69 Merged in SP-259-elliots-tas-algo-not-firing (pull request #369)
[RTM] SP-259 - Fix md exchange status transitions.

Approved-by: Jake Norbut <jake.norbut@bluetradesys.com>
2019-11-14 20:22:44 +00:00
Eric Harding 176c1f8d92 Update sdk overview.md with blog edits 2019-11-14 15:22:01 -05:00
Jake Norbut 8b0c9e7722 adding some TAS-style symbols so we get md recording on them 2019-11-14 07:56:27 -06:00
Kevin Darby 70e87151bc upstream changes for PR 2019-11-13 16:49:17 -05:00
Kevin Darby d1299f8a78 Merge branch 'dotnet' of bitbucket.org:bluetradesys/spark into vwap 2019-11-13 16:47:18 -05:00
Kevin Darby 20e58dc80b address PR concerns 2019-11-13 16:46:36 -05:00
Eric Harding a5c2e8b287 SP-230 Disable GMI_import for sdk 2019-11-13 15:37:38 -05:00
Eric Harding 24e766ba59 SP-230 include futures.coconut in dockerfile 2019-11-13 14:45:34 -05:00
Eric Harding ddd81ea93a Allow sdk shell to always skip stunnel 2019-11-13 14:45:06 -05:00
Eric Harding 5481cce34c Simple sparkd subprocess runner 2019-11-13 13:50:21 -05:00
Jake Norbut 58d39c4833 rendering ladder prices approparitely based on price_display_format 2019-11-13 10:38:26 -06:00
Jake Norbut 367d9be724 adding price_display_format to settings view 2019-11-13 10:38:04 -06:00
Jake Norbut 99f2ab7c8a adding price_display_format to vm 2019-11-13 10:37:46 -06:00
Jake Norbut 8b091b39eb adding PriceDisplayFormat enum to proto 2019-11-13 10:37:24 -06:00
Kevin Darby 9f7b0e5898 running twap from c#, need some stats 2019-11-12 18:12:06 -05:00
Kevin Darby 5e073c2330 interop with c++ algos kinda works 2019-11-12 17:56:25 -05:00
Eric Harding 9d1f0e5538 Remove bad symlink breaking build. 2019-11-12 16:58:30 -05:00
Eric Harding 02ade1e0c9 Merged in SP-230-api-experience (pull request #373)
SP-230 api experience
2019-11-12 21:36:11 +00:00
Eric Harding 296749bae3 remote docker part from udpate_github 2019-11-12 16:34:29 -05:00
Eric Harding 49ec9885eb Merge branch 'master' of bitbucket.org:bluetradesys/spark into SP-230-api-experience 2019-11-12 13:28:28 -05:00
Eric Harding 04264e70b9 add spark_client.cmd 2019-11-12 11:54:15 -05:00
Kevin Darby 1b425d9a7c Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-11-12 11:31:31 -05:00
Kevin Darby 3546b65c91 don't finalize 2019-11-12 11:18:24 -05:00
Eric Harding eaadc74242 SP-230 overview/blog 2019-11-12 10:56:29 -05:00
Eric Harding 6760ca1898 Always init_spark_plugin() for libspark.so 2019-11-12 08:50:31 -05:00
Kevin Darby 758da29e25 added assert I think works 2019-11-11 23:19:03 -05:00
Kevin Darby 60e246036b back to state where I can repl dan 2019-11-11 23:14:49 -05:00
Kevin Darby 4b34f959e6 skip default 2019-11-11 18:17:29 -05:00
Kevin Darby 8abbd24cbe bug in orderbook refactor 2019-11-11 17:57:19 -05:00
Kevin Darby 932f852d6a Merge branch 'dotnet' of bitbucket.org:bluetradesys/spark into vwap 2019-11-11 17:14:16 -05:00
Kevin Darby 5773945791 add data dir for .net in linux
make sparkcmd build in the right place on windows again
2019-11-11 17:12:55 -05:00
Kevin Darby bda1bd8f96 round trip algo runs on linux 2019-11-11 17:11:27 -05:00
Eric Harding 5f2d3c7c26 SP-230 algo overview draft 2019-11-11 16:49:12 -05:00
Eric Harding 326532ed5c Urls change /algo/ to /server/ 2019-11-11 11:43:31 -05:00
Eric Harding 5cfb4a65e9 SP-230 add faq/join 2019-11-11 10:19:17 -05:00
Kevin Darby c3632e02d3 Added NativeOrderWrapper for algo backtesting 2019-11-08 18:04:34 -05:00
Eric Harding f955fef680 SP-230 orders 2019-11-08 17:31:54 -05:00
Eric Harding 2214988442 SP-230 rename Algo sdk to Server sdk 2019-11-08 16:51:25 -05:00
Eric Harding e80ab05969 SP-230 subscriptions 2019-11-08 16:26:51 -05:00
Eric Harding 92bdbd460a initialization : editing 2019-11-08 15:43:31 -05:00
Jake Norbut a357d978ca misc string formatting fix; this is only used for debugging focus issues 2019-11-08 13:45:03 -06:00
Jake Norbut dfb673bd63 recenters all ladders via posting to appropriate tag to bus when spacebar is pressed over a ladder 2019-11-08 13:43:29 -06:00
Jake Norbut 24f366491b update view with appropriate controls for enforce_max_clip and max_clip 2019-11-08 10:44:03 -06:00
Jake Norbut 55134bf172 check max clip for crossing market dialog as well 2019-11-08 10:42:23 -06:00
Jake Norbut b6b33f14ef enforce max clip at order entry 2019-11-08 10:40:43 -06:00
Jake Norbut 12d532a17f adding enforce_max_clip and max_clip to settings vm 2019-11-08 10:39:38 -06:00
Jake Norbut 09679ff494 adding enforce_max_clip and max_clip to proto 2019-11-08 10:38:10 -06:00
Eric Harding 781e7c98a0 SP-230 initialization 2019-11-08 10:09:33 -05:00
Eric Harding 4189b05665 SP-262 check for directory exists in keep_n_matching_files 2019-11-07 18:08:13 -05:00
Kevin Darby 1b959b09c8 hooking c++ algos to algo backtest framework 2019-11-07 18:01:21 -05:00
Eric Harding ff5b04f8ee SP-259 - Fix md exchange status transitions. 2019-11-07 17:52:10 -05:00
Kevin Darby f55637ea08 Merge branch 'dotnet' of bitbucket.org:bluetradesys/spark into vwap 2019-11-06 21:36:57 -05:00
Kevin Darby 0272df9974 Merge branch 'vwap' of bitbucket.org:bluetradesys/spark into vwap 2019-11-06 21:34:45 -05:00
Kevin Darby 0e02428b79 change algoanalyzer startup for taha 2019-11-06 21:34:35 -05:00
Kevin Darby 721c889235 release mode uses published sparkcmd 2019-11-06 18:22:06 -05:00
Kevin Darby 9957af655f hooked sparkcmd linux build to the main server build stuff 2019-11-06 17:47:21 -05:00
Kevin Darby eab92fb486 damn windows casing 2019-11-06 13:55:29 -05:00
Kevin Darby 9f1cd47cfa hooking build to cmake 2019-11-06 13:55:07 -05:00
Kevin Darby 90c3edbbe7 adding core 2 back to docker per eric 2019-11-06 13:24:57 -05:00
Jake Norbut 4180b9a8ec removing price and quantity special case when legs = 3 2019-11-06 11:45:42 -06:00
Kevin Darby adee8b584c capitalized first letter of proto to work around a protoc bug 2019-11-06 12:43:27 -05:00
Kevin Darby 329ad323e0 delete protos to change case on windows 2019-11-06 12:41:37 -05:00
Kevin Darby a8473f9340 Capitalizing first letter of some protos because of a protoc bug 2019-11-06 12:31:58 -05:00
Kevin Darby 1c0115f8cf had to delete these protos to change case 2019-11-06 12:31:12 -05:00
Kevin Darby a6ef802d3f fix proj files 2019-11-05 18:38:17 -05:00
Kevin Darby 37b5c37015 merging dotnet branch 2019-11-05 18:24:24 -05:00
Kevin Darby 1e28e214a4 Merge branch 'dotnet' of bitbucket.org:bluetradesys/spark into vwap 2019-11-05 18:23:47 -05:00
Kevin Darby c713b97441 cleanup csproj 2019-11-05 18:23:09 -05:00
Kevin Darby 4e8525f015 Merge branch 'dotnet' of bitbucket.org:bluetradesys/spark into vwap 2019-11-05 18:21:40 -05:00
Kevin Darby eb79264b9b netcore builds on linux through dotnet build 2019-11-05 18:19:17 -05:00
Kevin Darby 9c359ddb33 for_taha 2019-11-05 16:38:01 -05:00
Kevin Darby 67a16d5085 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-11-03 23:20:44 -05:00
Eric Harding 5ba244c982 Editing initialization 2019-10-31 17:24:20 -04:00
Eric Harding 4029a6a58a registration.md 2019-10-31 16:48:06 -04:00
Eric Harding c03d05285b Copy images locally so Michael doesn't steal them 2019-10-28 17:15:18 -04:00
Kevin Darby 6049cc4b43 oil spreads seem to work 2019-10-26 22:38:13 -04:00
Kevin Darby d916180132 back to oil 2019-10-25 23:50:20 -04:00
Kevin Darby ad9f28f782 round trip treasuries...not great 2019-10-25 23:32:02 -04:00
Kevin Darby 2890e4ebcc rt spreader 2019-10-25 18:56:52 -04:00
Kevin Darby 6638e4c765 fixed spreads / outright arbitration 2019-10-25 18:50:04 -04:00
Eric Harding 78323d09e8 SP-230 Development with other editor 2019-10-25 17:40:10 -04:00
Eric Harding f2621da423 SP-230 Development with VScode 2019-10-25 12:19:38 -04:00
Kevin Darby a251a8f411 clone 2019-10-25 00:50:02 -04:00
Kevin Darby e7790679ca this isn't as fast as I thought it would be 2019-10-25 00:15:34 -04:00
Kevin Darby 2a5e777c15 this is better 2019-10-24 18:30:24 -04:00
Kevin Darby fdbbce9ff3 remove concept of pre_book, instead separate the book arrangement and the trade / cross processing and layer in our orders by timestamp 2019-10-24 18:25:06 -04:00
Eric Harding cf2bc03dd1 SP-230 Editing 2019-10-24 17:36:27 -04:00
Kevin Darby d47ac768c4 trying something 2019-10-24 16:30:21 -04:00
Kevin Darby 4867f4fa53 match event 2019-10-24 15:53:16 -04:00
Kevin Darby 902a99e7d0 new files 2019-10-24 14:30:13 -04:00
Kevin Darby faf5f664dc share one order book 2019-10-24 14:29:35 -04:00
Eric Harding 88e17743ef Disable onixs for sdk sparkd 2019-10-24 11:28:04 -04:00
Kevin Darby 4af94aaaa8 made some trades 2019-10-23 23:52:23 -04:00
Eric Harding 950073703f SP-230 Scripts to deploy to api.bluetradesys.com 2019-10-23 19:40:11 -04:00
Kevin Darby 2bea0a0a11 replicated some CL spread arbs 2019-10-23 18:34:40 -04:00
Kevin Darby b55067be91 trying 10/21 oil spreads 2019-10-23 00:24:21 -04:00
Kevin Darby 7ea20dbbff had to introduce concept of can_aggress-- if we're first in the queue we can't tell the difference between that and a cross 2019-10-22 23:50:07 -04:00
Kevin Darby 2dcf1424ea . 2019-10-22 18:21:30 -04:00
Kevin Darby caedb1ed64 round trip spreader taking shape 2019-10-22 18:15:13 -04:00
Eric Harding 504d09eb6c SP-230 devcontainers are pretty neat 2019-10-22 17:36:51 -04:00
Eric Harding c2ea5aa36f ServiceContext needs to include port when deciding to connect to sparkvm:8000 for debuggin 2019-10-22 16:35:00 -04:00
Kevin Darby d39856a93a refactor for multiple securities, implemented round tripper 2019-10-22 16:27:01 -04:00
Eric Harding c367488844 sdk: refactor example build 2019-10-22 13:02:10 -04:00
Kevin Darby f8c7cc87b9 complicated hierarchies 2019-10-22 00:07:35 -04:00
Kevin Darby ee9a9bd721 moving stuff around for spreader case 2019-10-21 18:21:21 -04:00
Kevin Darby 7520d3516a move pnl computation to orderbook 2019-10-21 12:37:12 -04:00
Kevin Darby a2a9df86fc now we need prorata 2019-10-20 22:18:36 -04:00
Kevin Darby aa31aa7a3e testing 2019-10-20 21:27:19 -04:00
Kevin Darby 950b8686f2 small bug here in change / cancel 2019-10-20 21:22:50 -04:00
Kevin Darby b6ab217a11 assert that we are moving forward in time 2019-10-20 21:21:59 -04:00
Kevin Darby 3b8176d326 status event 2019-10-20 21:19:49 -04:00
Kevin Darby e9ec07cb2b have to queue the hedge with latency 2019-10-20 01:13:12 -04:00
Kevin Darby 78659b5d20 if these treasury results are real we are getting into a new business 2019-10-20 00:25:07 -04:00
Kevin Darby 9e26a2c651 adding top 2019-10-19 21:42:08 -04:00
Kevin Darby 3243ce1a45 treasury roll 2019-10-18 23:58:11 -04:00
Kevin Darby 475b6ae25b peg, cover, lean 2019-10-18 22:48:17 -04:00
Kevin Darby b853af59d6 usings 2019-10-18 22:24:10 -04:00
Kevin Darby ded1ad42e7 arbitraged spread and futures streams, separated replay from sending 2019-10-18 22:13:30 -04:00
Kevin Darby f3541b6c7f added latency to the catalyst loop; my clock isn't great though because it relies on the tape 2019-10-18 17:21:55 -04:00
Kevin Darby 3c40c84c02 got the mbo fixed 2019-10-18 16:47:02 -04:00
Kevin Darby d50420edb9 cme can send order updates in MDEntry or OrderIdEntry.... 2019-10-18 15:06:37 -04:00
Kevin Darby e0794f0725 added some assertions, cleaning up, now have to look at q 2019-10-18 13:23:40 -04:00
Kevin Darby fb6282ae9e optimizations 2019-10-18 11:15:08 -04:00
Kevin Darby 23995e5cc6 shaping up 2019-10-17 23:52:20 -04:00
Kevin Darby 161545b864 jcl is small loss always joining at end of q 2019-10-17 22:10:30 -04:00
Kevin Darby 285250dded bugs 2019-10-17 18:22:23 -04:00
Kevin Darby bbc3e03e48 now lets look at this queue 2019-10-17 18:04:03 -04:00
Eric Harding fb19dd8ce5 Add sdk dockerfile and create it on build 2019-10-17 17:43:19 -04:00
Eric Harding c0a2c6a24a Split examples into separate directories and add devcontainer 2019-10-17 17:42:30 -04:00
Kevin Darby 6b8d0d203c partials work, the queue seems to have broken 2019-10-17 17:42:03 -04:00
Eric Harding 7cbd5adccc Advance linux docker to include 'zip' executable 2019-10-17 17:28:38 -04:00
Eric Harding 3b8a4f89cc Rename Log subsystem ClientSdk to just Sdk 2019-10-17 17:25:20 -04:00
Kevin Darby c0bec8cfa5 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-10-17 12:18:01 -04:00
Kevin Darby 19b0d8bf56 typo that I need to fix in master 2019-10-17 11:47:46 -04:00
Kevin Darby ede14ea7b3 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-10-17 11:40:24 -04:00
Kevin Darby 48ae7c4c33 this looks a lot like our c++ interface; I do not know if that's good 2019-10-17 11:36:35 -04:00
Kevin Darby fc217fd904 sweet replication 2019-10-16 23:23:16 -04:00
Kevin Darby b692a3e9d2 partial fills kinda kill everything 2019-10-16 18:37:13 -04:00
Kevin Darby 48f5e47335 now partial fills 2019-10-16 15:38:43 -04:00
Kevin Darby a080a0ccaa using sendingTime instead of transactTime 2019-10-16 14:45:13 -04:00
Kevin Darby 90321045f6 need to filter orders separately 2019-10-15 23:55:16 -04:00
Kevin Darby 8ad9e24415 interesting results 2019-10-15 23:26:10 -04:00
Kevin Darby 2008786c4e some semblance of a simulation going 2019-10-15 18:28:49 -04:00
Kevin Darby 57f8036796 jcl 2019-10-14 18:10:21 -04:00
Kevin Darby 21a304261e merge 2019-10-14 00:14:29 -04:00
Kevin Darby cefb2b2524 Merge branch 'fix' of bitbucket.org:bluetradesys/spark into vwap 2019-10-13 14:12:50 -04:00
Kevin Darby e26bdb228b Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-10-13 14:10:12 -04:00
Kevin Darby 1621ad03bf Merge branch 'master' of bitbucket.org:bluetradesys/spark into fix 2019-10-13 14:09:45 -04:00
Kevin Darby 174acf1597 getting join fills 2019-10-11 18:22:53 -04:00
Kevin Darby bf32c6133a mbo parsing in c# 2019-10-11 18:18:22 -04:00
Kevin Darby fe73874b19 more analysis 2019-10-11 17:28:12 -04:00
Kevin Darby 0eb82a0d5c inching towards a simulated pnl of an arbitrary strategy 2019-10-10 18:05:14 -04:00
Eric Harding 04f165b1a3 api docs: change info icon 2019-10-10 17:12:25 -04:00
Kevin Darby fc2165d85d CL, ZN, ZC exhibit spookily similar histograms, ES is a little different 2019-10-10 11:04:34 -04:00
Eric Harding 893aa7a370 api sdk - development 2019-10-09 20:01:56 -04:00
Eric Harding 245b5d0f99 sdk docs - downloading 2019-10-09 18:56:30 -04:00
Kevin Darby a368b2ea16 factored out analyzers so we can test Join/Cover/Lean and Spreader 2019-10-09 17:46:10 -04:00
Kevin Darby 6294ef6db2 made some headway in analysis 2019-10-09 16:25:44 -04:00
Eric Harding d5225aa75b spark sdk Installing 2019-10-09 12:21:03 -04:00
Eric Harding 48e6e1e139 client sections need work 2019-10-08 17:39:51 -04:00
Kevin Darby a9cca80c6d some corn stats 2019-10-08 17:36:16 -04:00
Eric Harding 1ebd0be57c api docs outline 2019-10-08 17:24:01 -04:00
Eric Harding 28779d333c api docs "landing page" 2019-10-08 16:53:40 -04:00
Eric Harding c9387a92be Add docs/api 2019-10-08 16:41:59 -04:00
Kevin Darby aee9066ccf cmake 2019-10-08 15:14:44 -04:00
Kevin Darby ea3c130738 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-10-08 13:13:56 -04:00
Kevin Darby 193f248f06 merge deleted some of my files 2019-10-07 17:40:01 -04:00
Kevin Darby 5212fb272e Merge branch 'master' of bitbucket.org:bluetradesys/spark into fix 2019-10-07 17:27:12 -04:00
Kevin Darby 6772c77e01 rudimentary fix orders seem to work 2019-10-07 17:18:20 -04:00
Kevin Darby 95c589f594 hooking up to run this fix server 2019-09-30 15:00:30 -04:00
Kevin Darby 699c7c5bfe Merge branch 'master' of bitbucket.org:bluetradesys/spark into fix 2019-09-30 12:02:13 -04:00
Kevin Darby 7de82b5685 Merge branch 'master' of bitbucket.org:bluetradesys/spark into fix 2019-09-30 11:45:44 -04:00
Kevin Darby a8e9d0d7d8 ordersession and dropcopy session code complete for native orders, time to debug 2019-09-27 18:21:35 -04:00
Kevin Darby d078e73179 order session 2019-09-27 17:58:36 -04:00
Kevin Darby 4351d6e66a drop copy session code complete 2019-09-27 17:04:42 -04:00
Kevin Darby 9850d6bde0 rx-cpp requires concurrent use with prescription medicine 2019-09-27 14:29:22 -04:00
Kevin Darby d23a072ad6 rx 2019-09-26 18:27:41 -04:00
Kevin Darby 6ef0808f49 never thought I'd use rxcpp...it's truly terrible; I feel physical pain 2019-09-26 18:16:48 -04:00
Kevin Darby e1c2d8aaaf it builds, ship it 2019-09-26 12:33:42 -04:00
Kevin Darby 719fd03063 nothing builds 2019-09-26 11:45:08 -04:00
Kevin Darby d436dae7cd more fix 2019-09-24 18:22:09 -04:00
Kevin Darby f66004b465 fix port 2019-09-24 14:37:30 -04:00
Kevin Darby aa8a56787b fix fix fix 2019-09-23 18:16:05 -04:00
Kevin Darby 35a69396f1 Merge branch 'master' of bitbucket.org:bluetradesys/spark into fix 2019-09-23 17:08:56 -04:00
Kevin Darby ddfb6d1105 update externals 2019-09-23 17:03:49 -04:00
Kevin Darby 005c0f9a5d c++ fix 2019-09-23 16:59:39 -04:00
Kevin Darby cf62eae51b replay book building 2019-09-06 18:13:16 -04:00
Kevin Darby c7e49e8d21 data replay 2019-09-05 18:47:04 -04:00
Kevin Darby 8bc420190b Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-09-05 18:46:53 -04:00
Kevin Darby 62711a144b got some replay 2019-09-05 14:14:41 -04:00
Kevin Darby 333273b48a testing 2019-09-04 17:41:48 -04:00
Kevin Darby dd194f8ac0 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-09-04 17:11:44 -04:00
Kevin Darby 5992f4814d testing replay 2019-09-04 17:02:06 -04:00
Kevin Darby d67f15b3fb Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-09-04 15:12:02 -04:00
Kevin Darby be8635788a Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-09-04 14:03:41 -04:00
Kevin Darby d96355e6c4 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-09-03 14:36:29 -04:00
Kevin Darby 4ef2c8a2da conf changes 2019-09-03 14:35:23 -04:00
Kevin Darby 058fbe1aee utils is not in mbts any longer 2019-09-02 17:14:41 -04:00
Kevin Darby bc0f9f574a Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-09-02 17:05:21 -04:00
Kevin Darby f575b82ce0 almost got the replay going 2019-08-30 17:54:58 -04:00
Kevin Darby 050ea18a02 generation 2019-08-30 00:17:00 -04:00
Kevin Darby 18829279d2 working on replay from parser 2019-08-29 17:44:55 -04:00
Kevin Darby 75703d54ea getting mbo from s3 2019-08-29 12:21:01 -04:00
Kevin Darby 0a3fc1bca0 s3 2019-08-28 18:52:02 -04:00
Kevin Darby bc688ef44d parsing mbo files 2019-08-28 17:47:29 -04:00
Kevin Darby 57af89b628 Merge branch 'master' of bitbucket.org:bluetradesys/spark into fix 2019-08-28 16:47:20 -04:00
Kevin Darby 4fcc70bcf0 mbo fix parser 2019-08-27 18:06:03 -04:00
Kevin Darby cad6f2c1eb Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-08-26 17:57:16 -04:00
Kevin Darby c16b898d86 scaffolding for historical data 2019-08-26 17:55:26 -04:00
Kevin Darby 4f98244c3a arrival 2019-08-23 22:23:59 -04:00
Kevin Darby 8770f98fb1 more algo 2019-08-19 11:54:23 -04:00
Kevin Darby bbcf78517f self adjust 2019-08-16 11:30:36 -04:00
Kevin Darby b9a940b4e3 adjust for my size 2019-08-15 18:00:55 -04:00
Kevin Darby d8a4c1aaf7 added VolumeSlicer hierarchy, VolumeSliceAlgo and POVAlgo 2019-08-15 17:41:23 -04:00
Kevin Darby 9803cf31c8 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-08-15 09:36:00 -04:00
Kevin Darby 4a36177992 externals with master 2019-08-14 16:17:19 -04:00
Kevin Darby 421614198a fixed external 2019-08-14 15:45:31 -04:00
Kevin Darby 51e227e921 timeslicer 2019-08-12 22:33:26 -04:00
Kevin Darby 74948d11c5 build 2019-08-12 18:33:00 -04:00
Kevin Darby f88e1b5903 build 2019-08-12 18:30:27 -04:00
Kevin Darby 59115ce886 volume estimator 2019-08-12 18:24:29 -04:00
Kevin Darby 4b18d15421 refactor into TimeSlicer and VolumeSlicer 2019-08-12 18:07:07 -04:00
Kevin Darby 9be591c634 need a slightly different hierarchy for pov 2019-08-12 16:08:46 -04:00
Kevin Darby 462af2f1f3 make offset algo support a negative offset which means cross 2019-08-12 14:20:45 -04:00
Kevin Darby ab35c943fd working on pov 2019-08-12 13:52:57 -04:00
Kevin Darby aa36b24165 slicer params 2019-08-12 11:11:27 -04:00
Kevin Darby 547cdda3db adding aggression params to base class 2019-08-11 16:06:01 -04:00
Kevin Darby 3b77fd1a6c peg price updates 2019-08-09 18:09:31 -04:00
Kevin Darby a8110c9a8d added peg algo to support vwap/twap 2019-08-09 17:58:09 -04:00
Kevin Darby b6f80d6a4a twap working ok 2019-08-09 14:52:25 -04:00
Kevin Darby 18489e64a2 twapping 2019-08-08 18:16:00 -04:00
Kevin Darby a3d2df9ba2 . 2019-08-08 16:44:35 -04:00
Kevin Darby 314700e2e7 residual quantity 2019-08-08 16:09:06 -04:00
Kevin Darby 461b6c15d6 twap bugs 2019-08-08 15:25:00 -04:00
Kevin Darby d23ac7e8ef allow generic order vm to reflect one level deep into protos to generate a gui; will need john's help on a datetimepicker 2019-08-08 14:54:34 -04:00
Kevin Darby 68c0179465 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-08-08 12:20:15 -04:00
Kevin Darby 8bc1455813 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-08-08 11:07:40 -04:00
Kevin Darby ecaa04ecf8 factor 2019-08-08 09:59:14 -04:00
Kevin Darby 44e3070544 add TimeSlicer 2019-08-08 00:05:41 -04:00
Kevin Darby 1815950835 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-08-07 17:31:50 -04:00
Kevin Darby 8762fbf7ce added twap to algo types 2019-08-06 18:20:10 -04:00
Kevin Darby 0459171d6e moved algo types to config 2019-08-06 18:15:47 -04:00
Kevin Darby fcdf72c5d9 Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-08-06 16:57:36 -04:00
Kevin Darby f5caf0b7ba twap bones 2019-08-06 16:57:02 -04:00
Kevin Darby a0f2673b3a basic timing structure down; maybe all these derive from twap 2019-08-05 23:51:28 -04:00
Kevin Darby ba3439b049 twap 2019-08-05 18:21:03 -04:00
Kevin Darby ae4d7f719b Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-08-02 17:57:21 -04:00
Kevin Darby 64916f6bfc Merge branch 'master' of bitbucket.org:bluetradesys/spark into vwap 2019-08-02 17:38:30 -04:00
Kevin Darby 1a9dd1c37a cleaning up this proto 2019-08-01 17:40:21 -04:00
Kevin Darby d77925c568 Merge branch 'prorata' of bitbucket.org:bluetradesys/spark into vwap 2019-08-01 17:11:38 -04:00
Kevin Darby f1f1b68ffb arrival 2019-07-03 22:14:39 -04:00
Kevin Darby 835f453f03 Merge branch 'prorata' of bitbucket.org:bluetradesys/spark into vwap 2019-07-03 15:17:09 -04:00
Kevin Darby 0eb9518485 didn't get far 2019-06-13 23:41:30 -04:00
Kevin Darby b5c70fc34e added price to slice 2019-06-11 23:56:11 -04:00
Kevin Darby a1dba1d7d0 historicaldataservice 2019-06-11 23:12:20 -04:00
Kevin Darby efdea5256f algoflow will probably not be in python 2019-06-11 21:07:55 -04:00
Kevin Darby 5df1e5f383 py notes 2019-06-09 22:50:46 -04:00
Kevin Darby 99750da31d beginnings of python driver for algo development. goal is to allow visual / interactive development environment for
more complex algos.  Will also offer backtesting of bts algos over MBO data.
2019-06-09 22:47:51 -04:00
Kevin Darby 49247dba3f externals 2019-06-09 21:58:11 -04:00
Kevin Darby a25257cb33 update externals for pybind 2019-06-08 23:33:43 -04:00
Kevin Darby b1c180d663 Merge branch 'prorata' of bitbucket.org:bluetradesys/spark into vwap 2019-06-07 16:01:49 -04:00
Kevin Darby 6afb16abcb bones for bluex orders 2019-06-07 15:53:25 -04:00
Kevin Darby 995fa3df35 . 2019-06-06 23:34:25 -04:00
Kevin Darby 18eb28dfd2 waps 2019-06-06 22:08:03 -04:00
Kevin Darby 99cdfadf8d bones for vwap, twap, arrivalprice, pov 2019-06-05 23:30:52 -04:00
Kevin Darby feab3cbb89 Merge branch 'master' of bitbucket.org:bluetradesys/spark into fix 2019-01-22 16:10:16 -05:00
Kevin Darby 1f7c1be194 Merge branch 'master' of bitbucket.org:bluetradesys/spark into fix 2018-12-28 13:51:59 -05:00
Kevin Darby f78f18b3b4 Merge branch 'master' of bitbucket.org:bluetradesys/spark into fix 2018-12-20 16:20:19 -05:00
Kevin Darby 6e7fa91718 ready for testing 2018-12-14 10:39:34 -05:00
Kevin Darby 8cac406547 fix error handling 2018-12-12 17:33:25 -05:00
Kevin Darby 0d83f28cbc fix lives 2018-12-12 14:26:03 -05:00
Kevin Darby 941f4bf837 Merge branch 'cleanup_mdclient' of bitbucket.org:bluetradesys/spark into fix 2018-12-11 23:05:35 -05:00
Kevin Darby 8bbe9cfd98 Merge branch 'master' of bitbucket.org:bluetradesys/spark into sdk_doc2 2018-12-06 12:56:02 -05:00
Kevin Darby ba633532eb hit a wall here with MDClient, going to refactor 2018-12-06 12:55:21 -05:00
Kevin Darby 7bf50415ca nearly ready for testing 2018-12-05 17:55:06 -05:00
Kevin Darby edbaa9c435 looks like we have dropcopy 2018-12-05 15:35:49 -05:00
Kevin Darby 7789f39c9d handle some messages 2018-12-04 18:20:23 -05:00
Kevin Darby 6e188b4f73 shaping up 2018-12-04 16:37:41 -05:00
Kevin Darby 33e8ff58c5 Merge branch 'master' of bitbucket.org:bluetradesys/spark into sdk_doc2 2018-12-04 09:42:30 -05:00
Kevin Darby 24ae03a9f8 access permissions api so fix session can report fills and orders 2018-12-03 18:19:20 -05:00
Kevin Darby 5fe0335e1a Merge branch 'master' of bitbucket.org:bluetradesys/spark into sdk_doc2 2018-12-03 17:02:34 -05:00
Kevin Darby 6cbf707094 Merge branch 'sdk_doc' of bitbucket.org:bluetradesys/spark into sdk_doc2 2018-12-03 16:06:58 -05:00
Kevin Darby 7e4ad55d9d established a session 2018-12-03 15:32:45 -05:00
Kevin Darby 35a0074014 bts fix44 adapter 2018-12-03 14:49:35 -05:00
Kevin Darby b8dd5c119d Merge branch 'sdk_doc' of bitbucket.org:bluetradesys/spark into sdk_doc2 2018-12-03 10:41:34 -05:00
Kevin Darby 8ada73aa64 Merge branch 'sdk_doc' of bitbucket.org:bluetradesys/spark into sdk_doc2 2018-11-30 18:37:39 -05:00
Kevin Darby a16ff30873 lets see how hard this is 2018-11-30 18:32:51 -05:00
408 changed files with 119999 additions and 776 deletions

No files matched your search

+4
View File
@@ -1,5 +1,7 @@
nohup.out
build/
build
cme_data/
cmake-build-debug/
.idea/
.dir-locals.el
@@ -34,3 +36,5 @@ trace_data/
/doc/user/public/*
.ionide/*
/.ignore
/build
/analysis_data
+130 -8
View File
@@ -46,7 +46,7 @@
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
},
{
"name": "(gdb) Launch",
"type": "cppdbg",
@@ -98,6 +98,46 @@
"externalConsole": true,
"requireExactSource": false
},
{
"name": "sparkcmd Launch",
"type": "clr",
"request": "launch",
"program": "${workspaceRoot}/build/Debug/bin/net471/sparkcmd.exe",
"args": [
"historical",
"--rstart", "11/20/2019",
"--rend", "11/29/2019",
"--rsymbol", "NG",
"--rsecuritytype", "Synthetic",
"--post_process_db", "NG_201911_W4",
"--post_process_db_host", "bigblue",
],
"cwd": "${workspaceRoot}",
"stopAtEntry": false,
"externalConsole": true,
"requireExactSource": false
},
{
"name": "sparkcmd simulation",
"type": "clr",
"request": "launch",
"program": "${workspaceRoot}/build/Debug/bin/net471/sparkcmd.exe",
"args": [
"historical",
"--rstart", "11/26/2019",
"--rend", "11/26/2019",
"--rsymbol", "ZN",
"--rsecuritytype", "Synthetic",
"--algo_security", "ZNH0;ZNZ9-ZNH0;ZNZ9",
"--algo_type", "RoundTrip",
"--algo_params", "size=10;tick_size=0.015625,0.0078125,0.015625;hedge_factors=1,1,-1",
"--skip_preanalysis", "true",
],
"cwd": "${workspaceRoot}",
"stopAtEntry": false,
"externalConsole": true,
"requireExactSource": false
},
{
"name": "Excel Launch",
"type": "clr",
@@ -131,6 +171,18 @@
"request": "attach",
"processId": "${command:pickProcess}"
},
{
"name": ".NET Framework Attach",
"type": "clr",
"request": "attach",
"processId": "${command:pickProcess}"
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
},
{
"name": "Spreader Tests",
"type": "cppdbg",
@@ -342,15 +394,19 @@
"justMyCode": true
},
{
"name": ".NET Core Remote Launch",
"name": "sparkcmd vsdbg (c#)",
"type": "coreclr",
"request": "launch",
"program": "/usr/bin/dotnet",
"program": "sparkcmd",
"args": [
"sparkcmd.dll",
"test",
"test_join_create_and_takeout_market"
"historical",
"--rstart", "11/20/2019",
"--rend", "11/20/2019",
"--rsymbol", "CL",
"--rsecuritytype", "Spread",
"--post_process_db", "mbo_history",
],
"env": {"LD_LIBRARY_PATH" : "."},
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/server",
"pipeTransport": {
@@ -361,11 +417,77 @@
"debuggerPath": "/home/bts/vsdbg/vsdbg",
"pipeCwd": "${workspaceRoot}",
"quoteArgs": true
},
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
},
"justMyCode": false
},
},
{
"name": "sparkcmd gdb (c++)",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/server/sparkcmd",
"args": [
"historical",
"--rstart", "10/21/2019",
"--rend", "10/21/2019",
"--rsymbol", "CL",
"--rsecuritytype", "Future",
"--algo_security", "CLX9",
"--algo_type", "TWAP",
"--algo_params", "'size=100;profit_ticks=1;tick_size=1,1,1;;hedge_factors=1,1,-1'",
"--skip_preanalysis", "true",
],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/server/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"logging": {
"engineLogging": false
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
},
{
"description": "Skip STL",
"text": "skip -gfi /usr/include/c++/7/bits/*.h",
"ignoreFailures": true
},
{
"description": "LD LIBRARY",
"text": "set env LD_LIBRARY_PATH=.",
"ignoreFailures": false
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": [
"bts@sparkvm"
],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "Jupyter notebook",
"type": "coreclr",
"request": "launch",
"program": "jupyter",
"args": ["notebook", "--notebook-dir=c:\\code\\bts\\spark\\src\\client\\spark_historical\\Notebooks"],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "internalConsole",
},
]
}
+11 -2
View File
@@ -48,6 +48,7 @@ else ()
add_subdirectory(doc/user)
add_subdirectory(src/sdk)
add_subdirectory(src/data_files)
add_subdirectory(src/client)
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/server
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/server
@@ -58,9 +59,17 @@ else ()
COMMAND ln ARGS -sf ${EXTERNALS_ROOT}/lib/Release/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.13.0.0 ${CMAKE_BINARY_DIR}/server
COMMAND ln ARGS -sf ${EXTERNALS_ROOT}/lib/Release/libACE-5.7.5.so ${CMAKE_BINARY_DIR}/server
COMMAND mkdir ARGS -p ${CMAKE_BINARY_DIR}/server/plugins
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/sdk/examples/order_plugin_example.so ${CMAKE_BINARY_DIR}/server/plugins/
COMMENT "Creating server runtime layout"
DEPENDS sparkd data_files_dir)
DEPENDS sparkd data_files_dir spark_client_dir)
add_custom_target(server_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/server)
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
add_custom_command(TARGET server_layout POST_BUILD
COMMAND ln -fs ${CMAKE_BINARY_DIR}/../${CMAKE_BUILD_TYPE}/bin/netcoreapp3.0/linux-x64/sparkcmd ${CMAKE_BINARY_DIR}/server/ )
else()
add_custom_command(TARGET server_layout POST_BUILD
COMMAND ln -fs ${CMAKE_BINARY_DIR}/../${CMAKE_BUILD_TYPE}/bin/netcoreapp3.0/linux-x64/publish/sparkcmd ${CMAKE_BINARY_DIR}/server/ )
endif()
endif()
+1
View File
@@ -0,0 +1 @@
public
+15
View File
@@ -0,0 +1,15 @@
# The URL the site will be built for
base_url = "https://api.bluetradesys.com"
title = "BTS Spark API"
description = "Documentation for the BTS Spark API"
compile_sass = true
highlight_code = true
highlight_theme = "kronuz"
insert_anchor_links = true
build_search_index = true
[extra]
author = "Blue Trading Systems"
+5
View File
@@ -0,0 +1,5 @@
+++
title = "BTS Spark API"
+++
This is index
+7
View File
@@ -0,0 +1,7 @@
+++
title="Client API"
template="client.html"
sort_by="weight"
+++
@@ -0,0 +1,7 @@
+++
title="Getting Started"
template="client.html"
sort_by="weight"
weight = 1
+++
@@ -0,0 +1,9 @@
+++
title = "Install Prerequisites"
template="client.html"
weight = 1
+++
## Coming Soon
* Install .net core
+25
View File
@@ -0,0 +1,25 @@
+++
title="Algo API"
template="documentation.html"
redirect_to = "server/getting-started/overview/"
sort_by="weight"
+++
Getting Started
- Install (docker, editor)
- Downloading
- Write your first algo
- Testing
Reference
- Subscriptions
- Child Orders
- Detaching
- Attaching
- ...
Samples
- Iceberg
- Pro-rata
@@ -0,0 +1,7 @@
+++
title="Getting Started"
template="documentation.html"
sort_by="weight"
weight = 1
+++
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

@@ -0,0 +1,138 @@
+++
title = "Development"
weight = 3
+++
# Visual Studio Code
In this section we're going to use the Remote - Containers feature of <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code<i class="fa fa-fw fa-window-restore" aria-hidden="true"></i></a> to simplify the development experience. If you are using a different editor skip to the <a href="#other-editors">other editor</a> section below.
## Remote - Containers
The Visual Studio Code Remote containers extension allows it to run a complete development environment inside the Spark SDK Docker container. The editor UI runs as a thin client on your desktop and connects to a headless instance running inside the Spark SDK Docker environment. This configuration allows us to ship a pre-configured set of [Tasks](https://code.visualstudio.com/Docs/editor/tasks) for building and testing your code.
Start Visual Studio Code and click on the puzzle piece icon on the left-hand side to open the extensions panel. Use the search box at the top to find the "Remote - Containers" extension and install it.
<img src="../vscode_remote_containers.png" width="640" />
## Into the Code
Open the examples/algo_template directory using the File->Open Folder menu option. If you opted to add it to your path during install, you could run `code .` from your command prompt.
When the workspace opens, you should see a notification offering to let you re-open the workspace inside the container.
<img src="../vscode_notification.png" width="480" />
The first time you open the workspace inside the container it will take a few seconds to configure the spark_sdk docker container. While the workspace is open in Visual Studio Code the docker image will also be running in the background. The container will stop automatically when you close the editor.
Open algo_template.cpp from the file browser on the left or by pressing ctrl-p and typing the name. Each Algo is a standard C++ class which implements **IAlgoOrder**. Placing your cursor on IAlgoOrder and pressing F12 will take you to the IAlgoOrder.h header file where you can browse the API. To learn more about how an Algo is instantiated see the [Algo Initialization](/server/ref/initialization).
## Compiling
To build press "Ctrl+Shift+B". You should see the build output at the bottom of your screen. If the build was successful the resulting algo_template.so will be automatically copied to the plugins directory where it will be loaded by the Spark server process on start.
<img src="../compiled.png" width="640" />
## Debugging
To debug your Algo set a breakpoint (F9) and open the Debug panel (Ctrl+Shift+D) and choose "(gdb) Launch". This will launch the Spark Server inside the container with the debugger attached.
<img src="../gdb_launch.png" width="380" />
With sparkd running you can launch the Spark Client (spark_client.cmd) and it will connect to the running server. Log in with the user "bts" and no password and open a ladder. You can now select your Algo on the order type dropdown and activate it by clicking on a price on the ladder.
<img src="../myalgo.png" width="150" />
While sparkd is running you can also access the Spark Server Admin interface on [http://localhost:9000](http://localhost:9000). Use the same "bts" login to access the admin interface. Here you can manage user and account permissions and risk limits.
## Starting Spark Server
To start the Spark Server without attaching a debugger press "Ctrl+Shift+P" and select "Tasks: Run Task" and then "Start Sparkd" and "Never scan task output" This will open a new terminal where you can see any messages logged with the **Sdk** subsystem as well as any warnings or errors. To stop the Spark server simply kill the terminal (trash can icon) or run the "Stop Sparkd" task.
## Next Steps
If you would like to understand more about how Docker is working behind the scenes continue to the [next section](#other-editors). Otherwise, continue to [Algo Registration](/server/ref/registration) to learn how Algos are registered with the Spark.
<hr>
# Other Editors
In this section you will be more exposed to the details of how Docker works and how to compile and test your Algo using the command line.
## Docker
Spark Server is built and runs only on Linux so you need a Linux development environment to effectively develop plug-ins for it. Docker lets you take the spark_sdk.img disk image and run it inside a virtual Linux machine running on your Windows desktop.
First, some terminology. A Docker "image" is a disk image containing a complete filesystem. The spark_sdk.img file you imported earlier is an image. A Docker "container" is what you get when you get when you attach this image to a running Linux system. You can connect to a running container and use it to run commands like the C++ compiler or the Spark server. Directories from your local filesystem can be mapped into the Docker container when it starts so you can easily share files.
### Start
The first step is to start the spark_sdk Docker container with the examples directory mapped so we can compile the examples inside the container. In your command prompt cd to the *examples* directory that you unzipped from the spark_sdk.zip file. Then run the following command to start the container.
Windows Command Prompt:
{% clipable() %}
docker run --rm -it -v %CD%:/examples -u bts -w /examples --shm-size 1024m --name spark_sdk -h spark_sdk --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 9000:9000 -p 9001:9001 spark_sdk bash
{% end %}
**Powershell** / Linux / Mac:
{% clipable() %}
docker run --rm -it -v ${PWD}:/examples -u bts -w /examples --shm-size 1024m --name spark_sdk -h spark_sdk --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 9000:9000 -p 9001:9001 spark_sdk bash
{% end %}
### Attach
The container will remain as long as this prompt is open. You can attach an additional to the running container with the following command:
{% clipable() %}
docker exec -it spark_sdk bash
{% end %}
## Compiling
Let's look at the algo_template sample first. All of the samples are laid out similarly with a `build.sh` script for compiling. As long as you are running build.sh inside the spark Docker container, it automatically copies the build output to /sparkbin/plugins/ where it needs to be to get loaded by the Spark server.
```
bts@spark_sdk:/examples$ cd algo_template/
bts@spark_sdk:/examples/algo_template$ ./build.sh
algo_template.so copied to /sparkbin/plugins/
Restart sparkd to see changes.
```
## Starting Spark Server
To start the Spark server `cd /sparkbin/` and run `./sparkd run`. Press Ctrl+C to stop it.
```
bts@spark_sdk:/sparkbin$ ./sparkd run
2019-10-25 16:21:09.383626|262552152803600|Gen|Warn |1 |main|132 |Run.cpp:53 |dev|
------------------------------------ Sparkd launched --------------------------------
```
You will see any Sdk log messages as well as any log messages at or above Warning level from other parts of the system. If you need additional diagnostic information more details logs are stored in /sparkdata/data/logging/log. These logs will be automatically deleted when you stop the Docker container.
With sparkd running you can launch the Spark Client (spark_client.cmd) and it will connect to the running server. Log in with the user "bts" and no password and open a ladder. You can now select your Algo on the order type dropdown and activate it by clicking on a price on the ladder.
<img src="../myalgo.png" width="150" />
While sparkd is running you can also access the Spark Server Admin interface on [http://localhost:9000](http://localhost:9000). Use the same "bts" login to access the admin interface. Here you can manage user and account permissions and risk limits.
## Debugging
You can debug your algo using gdb from the bash command prompt.
```bts@spark_sdk:/sparkbin$ gdb --args ./sparkd run
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
...
Reading symbols from ./sparkd...done.
(gdb) break algo_template.cpp:45
No source file named algo_template.cpp.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (algo_template.cpp:45) pending.
(gdb) run
Starting program: /sparkbin/sparkd run
```
If your editor supports debugging over the ssh protocol you can start sshd from inside the container.
## Next
Continue to [Algo Registration](/server/ref/registration) to learn how Algos are registered with the Spark.
Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

@@ -0,0 +1,79 @@
+++
title = "Download SDK"
weight = 2
+++
## Request Access 🔑
To start using the Server SDK you will need to request access though our sales department. Please email <a href="mailto:info@bluetradesys.com">info@bluetradesys.com</a> or call <a href="tel:919-913-0850">(919) 913-0850</a> and we will provide download credentials.
## Download
Download the latest SDK image here: [spark_sdk.zip](https://api.bluetradesys.com/download/spark_sdk.zip)
Unzip that folder into a working directory. Inside you should see something like this:
```
spark_sdk.img
client/
spark_client.cmd
examples/
```
## Import
Import the spark_sdk image into docker using the `docker load` command.
{% clipable() %}
docker load < spark_sdk.img
{% end %}
<div class="info">
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
<strong>If you see this error it means Docker Desktop is not running:</strong>
error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.40/images/json: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuration on Windows, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running.
</div>
Confirm that the import worked by running `docker images` which should list the new image.
```
c:\bts> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
bluetradingsystems/spark_sdk latest e2be89436e73 4 hours ago 3.89GB
```
<!--
## Run
Start the docker container by running
```
docker run -d -v %CD%:/work --name spark_sdk --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8000:8000 -p 8001:8001 -p 8008:8008 bluetradingsytems/spark_sdk
```
<div class="linux">
<i class="fa fa-linux fa-fw" aria-hidden="true"></i>
If you are using Linux or Mac replace <strong>%CD%</strong> with <strong>$PWD</strong>.
</div>
The first time you invoke `docker run` you may be prompted to "share" your filesystem with Docker. This usually works fine but if you run into trouble, see <a href="">Docker Desktop for Windows tips</a> on avoiding common problems.
## Success 🎉
Docker is now running the spark SDK image. If you are on Windows or Mac it is running inside a virtual Linux machine. You can see that is is running by typing `docker ps` to list running docker containers. If you restart the Docker Desktop application you will need to start the spark_sdk image again using `docker start spark_sdk`.
You should now be able to access an admin interface at http://localhost:8008/ which will let you stop and start the spark server process.
-->
## Update
To update your Spark SDK simply download an unzip a new [spark_sdk.zip](https://api.bluetradesys.com/download/spark_sdk.zip) and use `docker load < spark_sdk.img` to overwrite the old image with the new one.
To preserve the old image so you can go back to it later run `docker tag spark_sdk spark_sdk:your_custom_tag` before loading the new SDK image.
<!--
Then stop, remove and restart spark_sdk.
```
c:\bts> docker stop spark_sdk
c:\bts> docker rm spark_sdk
c:\bts> docker run -d -v %cd%:/sdk --name spark_sdk bluetradingsytems/spark_sdk
``` -->
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

@@ -0,0 +1,57 @@
+++
title = "Install Prerequisites"
weight = 1
+++
These instructions assume you are using Microsoft Windows but you should be able to follow them on a Linux or Mac with minor modifications.
{% linux() %}
When there is a significant difference on non-Windows platforms it will be called out in a box like this one.
{% end %}
{% info() %}
Tips or solutions to common problems will be highlighted in a box like this.
{% end %}
The minimum hardware requirements for using the SDK are:
- **12 GB** RAM (preferably 16 GB or more)
- 4 CPU cores
- 20 GB free hard disk space
The Spark SDK uses a tool called Docker to distribute all of the tools you need to build and test your trading algorithm ("Algo"). Once you have Docker installed you can download and import the Spark SDK image and be ready to start developing your Algo in a few minutes.
## Docker
Download and install <a href="https://www.docker.com/products/docker-desktop" target="_blank">Docker Desktop for Windows/Mac. <i class="fa fa-fw fa-window-restore" aria-hidden="true"></i></a>
<div class="linux">
<i class="fa fa-linux fa-fw" aria-hidden="true"></i>
If you are using Linux follow the <a href="https://docs.docker.com/install/#supported-platforms">official install instructions for Docker for your distribution.</a>
</div>
During the install Docker may ask you to enable virtualization support and reboot.
Once Docker Desktop is installed and running it will create an icon in your system tray area that looks like the Docker logo.
![](../docker_tray.png)
Right click on the tray icon and choose 'Settings' and choose the 'Advanced' tab.
Ensure that the docker image has 8192 MB of memory and at least 2 cores. Memory that you assign to the docker image will not be available to Windows/Mac while Docker is running. CPU cores are shared with the host OS. Since you are going to use this image to compile your Algo it makes sense to allow Docker to use all available cores.
<img src="../docker_config.png" width="640" >
## Sharing
You need to give Docker access to the Windows drive where your source code is kept.
Open Settings -> Shared Drives and check the drive where you intend to keep your Algo source code.
<div class="info">
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
If you run into trouble with drive sharing, see <a href="https://code.visualstudio.com/docs/remote/troubleshooting#_docker-desktop-for-windows-tips">Docker Desktop for Windows tips</a> on avoiding common problems.
</div>
## Editor
The Server SDK includes a complete configuration for C++ development with the <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code <i class="fa fa-fw fa-window-restore" aria-hidden="true"></i></a> editor. If you are a new to C++ development on a Linux system we recommend you give this a try as it's the easiest way to get up and running quickly. Of course, If you have a different editor that you prefer we fully support that as well.
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@@ -0,0 +1,44 @@
+++
title = "Overview"
weight = 0
+++
Using the **Spark Server SDK**, users can create new order types ("Algos"). In this case, users implement the new functionality in C++, producing a shared library that is loaded at run time by our Spark Server.
If you are interested in accessing Spark server remotely, please see the [Spark Client SDK](/client/).
## Speed
The Spark platform offers a sub-10 microsecond socket to socket response times for algorithmic trading. With the **Spark Server SDK**, you can create your order types in high-performance C++ and load them into the Spark server.
Since your order is running inside the Spark Server, there is virtually no overhead allowing your algorithm to take full advantage of the speed Spark offers. Hosting a high-performance language like C++ directly in the Spark server process allows it to respond to the market thousands of times faster than an Algo built using a proprietary drag and drop tool.
## Easy to Get Started
If you are not actively developing with C++, it can be time-consuming to set up a complete development environment from scratch. That is why we provide a full development environment out of the box with [Docker](https://docker.io) so you can download and try the Server SDK quickly and easily.
Docker works across Windows, macOS, and Linux, so you don't need to change your development environment to try the Spark API. Docker also ensures that all of the dependencies you need are packaged together in one image, so you know it will work out of the box, no matter the platform.
## Implementation
Creating a new Algo begins with implementing a standard C++ class derived from IAlgoOrder. Start from the [algo_template](/server/samples/template) example to get going quickly.
The first call your new Algo receives is [do_before_launch](/server/ref/initialization#before-launch), which is an opportunity to validate parameters and allocate any long-lived resources needed during execution. Next, it receives either [do_launch](/server/ref/initialization#launch-launch-attached) in the case of a new order or [do_launch_attached](/server/ref/initialization#launch-launch-attached) if the order is attaching to an existing order.
The Algo receives a reference to [IAlgoServices](/server/ref/subscriptions/), which is how it calls out to the Spark system. It will use [IAlgoServices](/server/ref/subscriptions/) to subscribe to market events, launch and control child orders, and communicate its state to the larger Spark system.
## Fully Integrated
When a Spark Server plugin is loaded, it registers its exposed Algos with the Spark Server though the [init_spark_plugin](/server/ref/registration) callback. This callback allows the Algo to describe the parameters it expects so they can be automatically entered in the [Spark Client](https://www.bluetradingsystems.com/bts-spark/).
<img src="../myalgo.png" width="150" />
<img src="../paramsui.png" width="460" />
Compose your Algo with out of the box Algos in the [Spark Algo Studio](https://www.bluetradingsystems.com/news/155-bts-algo-studio-provides-algo-library-with-customization-functionality) to create new functionality on the fly.
<img src="../algostudio.png" width="548" /><br />
<img src="../iced_algo.png" width="460" />
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

+7
View File
@@ -0,0 +1,7 @@
+++
title="Reference"
template="documentation.html"
sort_by="weight"
weight = 2
+++
+8
View File
@@ -0,0 +1,8 @@
+++
title = "Questions"
weight = 40
+++
## I need to make a call that might take a few seconds. What is the best way to do this?
Create a background thread in [do_before_launch](/server/ref/initialization#before-launch) or [do_launch](/server/ref/initialization#launch-launch-attached) to do the work. Use [on_timer](/server/ref/subscriptions#timer) to poll until the result is available.
@@ -0,0 +1,97 @@
+++
title = "Initialization"
weight = 10
+++
Each Algo derives from IAlgoOrder and overrides virtual methods to receive callbacks from the Spark system.
## Before Launch
When an order is activated by a user or by another Algo, the first call it receives is do_before_launch. This call happens outside of the latency-sensitive path, so it's the place to validate parameters and set up data structures that the Algo might need.
This call returns an OrderOpResult, which allows it to fail and return an error message to its creator. If a user created this order, this message is displayed in the [Activity Log](https://www.bluetradingsystems.com/docs/bts_spark/Help/#activity-log) and across the bottom of the ladder.
Every SDK Algo is a "Dynamic" Algo since it's parameters are defined during [registration](/server/ref/registration/). Use the `get_if<T>` helper to retrieve a named parameter from the `order_params` collection as a `std::option<T>`. If a parameter has a valid default value you can use `std::option::value_or(...)` to set default values for missing parameters. If a parameter *must* exist or must be within a certain valid range, return an error to the caller.
```cpp
OrderOpResult MyAlgo::do_before_launch(IBeforeLaunchAlgoServices& serv) {
auto& def = serv.definition();
auto& params = def.custom_def().dynamic().order_params();
auto mqi = get_if<uint32_t>(params, "Min Quantity");
if (!mqi || mqi.value() == 0)
return OrderOpResult{
ORDER_ERROR_INVALID_ORDER_DEFINITON,
"Min Quantity parameter must be defined and non zero"};
}
```
<div class="info">
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
The parameters are defined during <a href="/server/ref/registration/">registration</a> by the <a href="/server/ref/registration/#dynamicorderdescriptor">DynamicOrderDescriptor</a>.
</div>
### IBeforeLaunchAlgoServices
IBeforeLaunchAlgoServices is passed to `do_before_launch` and allows the Algo to query its environment.
```cpp
class IBeforeLaunchAlgoServices {
public:
// The OrderDefinition for this algo
virtual api::orderman::OrderDefinition const &definition() const = 0;
// The security this algo is paramterized with (also available from
// definition())
virtual api::Security const &security() const = 0;
// The unique order key for this algo
virtual OrderKey order_key() const = 0;
// The parent key for this algo's parent or null_order_key() if the
// algo does not have a parent
virtual OrderKey parent_order_key() const = 0;
// The security identified by k or nullptr if no such security exists
virtual api::Security const *lookup_security(SecurityKey k) const = 0;
// Wheter this algo is being attached to an existing order.
// If an algo does not support attaching it can return an error
// if is_attaching() == true from do_before_launch.
virtual bool is_attaching() const = 0;
// Build a child template that can later can be used to quickly
// launch child orders. The reserve parameter indicates how many
// orders should be created ahead of time, before they are
// launched. This is usefull to remove the relatively expensive
// order creation operation to a background thread.
virtual ChildTemplate &
make_child_template(api::orderman::OrderDefinition const &child_def,
size_t reserve = 1) = 0;
// Get the current time
virtual TimeStamp get_time() const;
};
```
## Launch / Launch Attached
Depending on the state of `is_attaching()` the next call will either be `do_launch` or `do_launch_attached`. The only difference is that in `do_launch_attached` the existing OrderKey and ChildState are provided.
`do_launch` and `do_launch_attached` are in the latency-sensitive path and should not do more work than needed. These functions get a reference to `IAlgoServices`, which is a superset of the functionality available on `IBeforeLaunchAlgoServices`. Most Algos should store a pointer or reference to this object for managing child orders (it has a stable address).
Now is the time to use `IAlgoServices` to subscribe to market events that are relevant to your Algo and create any child orders that need to exist at the start of your Algo. You can safely call IAlgoServices from any `IAlgoOrder` callback.
To learn more about subscribing to events see [subscriptions](/server/ref/subscriptions).
### Things to do in the launch callback
☑ Store a reference to IAlgoServices
☑ Subscribe to relevant market events
☑ Launch a child order?
## Update
If the user or parent Algo changes the order parameters (price, size, or the custom parameters defined during registration), Spark calls the `do_update` callback with the new parameters. It is up to the Algo to decide how to apply the new parameters to update the running state. It can do this by canceling, changing, or adding new child orders.
+88
View File
@@ -0,0 +1,88 @@
+++
title = "Child Orders"
weight = 30
+++
Every Algo must, at some point, launch a child order to be useful. Each child order can be another Algo or regular exchange order. When the child order is updated or filled, those changes are also sent to the parent.
# Templates
Since launching a child order is one of the most latency-sensitive things an Algo can do, the Server SDK enables you to create a child template. An order template prepares an order based on a known OrderDefinition and gets it ready to send on a background thread. When the Algo determines it is time to send the order, it only needs to provide the price and quantity to complete and send the order. If an Algo expects to send multiple child orders, it can reserve more than one. Preparing a child template is typically done in [do_before_launch](http://127.0.0.1:1111/server/ref/initialization/#before-launch) callback.
```cpp
virtual ChildTemplate&
IBeforeLaunchAlgoServices::make_child_template(
api::orderman::OrderDefinition const &child_def,
size_t reserve = 1);
```
# Launch
IAlgoServices provides two overloads for launching child orders. By default, launching a child order automatically subscribes the Algo to its state changes.
Launch a child order from a template if you have one prepared. This is the fastest option.
```cpp
OrderKey IAlgoServices::launch_child(ChildTemplate&, Price, Quantity, bool subscribe = true);
```
Launch a child order by constructing an OrderDefinition as needed.
```cpp
OrderKey launch_child(OrderDefinition const &, Price, Quantity, bool subscribe = true);
```
When a child is launched its `OrderKey` is returned to the caller. This ID can be used to update, cancel, or detach the child order.
## Update
To update an existing child order, call update_child and pass an Update. The Update type lets you change the price, size or the entire OrderDefinition. You only need to specify the fields that you intend to update so only set the price() field if that is what you are changing.
```cpp
void IAlgoServices::update_child(OrderKey child, api::orderman::Update const &);
```
## Cancel
To cancel an existing child order call `cancel_child`. When the order is canceled you will receive an update though the `on_child_change` callback.
```cpp
void IAlgoServices::cancel_child(OrderKey child);
```
## Detach
The lifetime of a child order is tied to its parent. If a parent is canceled or completed child orders are automatically stopped as well. If the Algo needs to launch an order that will continue after the Algo ends use `detach_child` to sever the connection. This order hierarchy can be viewed in the Spark [Order Book](https://www.bluetradingsystems.com/docs/bts_spark/Trading/#order-book).
```cpp
void IAlgoServices::detach_child(OrderKey child);
```
To detach all children at once use `detach_all_children`.
```cpp
void IAlgoServices::detach_all_children();
```
# Child Updated
When a child order is updated the parent receives the `on_child_change` callback with an updated ChildState object.
```cpp
void on_child_change(OrderKey, ChildState const &) override;
struct ChildState {
Price price;
Quantity quantity;
Quantity total_fills;
Price avg_price;
Quantity last_fills;
Price last_price;
ChildStatus status;
Quantity fills_at_attach_time;
};
```
<!--
To talk about:
- updating fills (update_fill_state)
- handling child finished (unexpected cancel)
-->
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

@@ -0,0 +1,92 @@
+++
title = "Registration"
weight = 1
+++
When Spark Server starts, it loads all plugins listed in the /sparkbin/plugins directory and calls an exported function named `init_spark_plugin` which must have the following signature.
```cpp
extern "C" void init_spark_plugin(bts::SparkServices &serv) { }
```
The `init_spark_plugin` function registers the Algo with a DynamicOrderDescriptor. Once registered, the Algo appears in the [Spark ladder](https://www.bluetradingsystems.com/docs/bts_spark/Trading/#ladder) and the [Algo Studio](https://www.bluetradingsystems.com/docs/bts_spark/Trading/#algo-studio).
To register an Algo call `register_dynamic_algo_order` on the provided bts::SparkServices instance. This function takes the DynamicOrderDescriptor and a function that is called to construct the IAlgoOrder. A single init_spark_plugin can call register_dynamic_algo_order multiple times to register multiple Algos.
The DynamicOrderDescriptor must have a dynamic_order_type (name), or the registration will fail.
```cpp
DynamicOrderDescriptor desc;
desc.set_dynamic_order_type("My Algo");
auto result =
serv.register_dynamic_algo_order(
desc, []() { return std::make_unique<MyAlgo>(); });
if (result != bts::AlgoRegistrationResult::SUCCESS) {
// Algo failed to register
}
```
## DynamicOrderDescriptor
The DynamicOrderDescriptor describes the type of parameters that the Algo accepts. These inputs can come either from the user manually entering them or from a parent Algo. Spark Algos are composable, so one Algo can activate another. See [Child Orders](/server/ref/orders) for more on how to activate custom order types as child orders.
Add parameters to the DynamicOrderDescriptor by calling `add_param_desc()` and setting the name and parameter type.
```cpp
*desc.add_param_desc() = param_bool("Enable Feature");
*desc.add_param_desc() = param_uint32("Feature Quantity");
```
The above parameters look like this when rendered in the Spark ladder.
<img src="../paramsui.png" width="460" />
And like this when viewed in the Spark order book.
<img src="../orderbook_truncated.png" width="988" />
Each descriptor can be one of the following types:
```
// Primitive
int32
uint32
double
string
bool
// Complex
Order
Array
Struct
```
**Currently the Spark UI only renders parameters with primitive types.** The complex types can only be provided by a parent order.
### Order
This parameter type indicates that another order type parameterizes this Algo. When the Algo needs to create a child order, it can use this parameter type to create a custom order type instead of defaulting to a limit order.
For example, an Algo might be designed to wait for a specific market condition before putting in an order. Instead of placing a limit order when the condition is met, the user can specify that it should an IceBerg order. The Algo doesn't need special logic to handle different child order types.
### Array
An array parameter is a collection of the same type of parameter. If your Algo needed to behave differently depending on a table of prices, you could send that list in though an array parameter.
```cpp
*desc.add_param_desc() =
param_array("Price Points",
param_double("unused").param_type());
```
### Struct
A struct parameter is a set of named parameter types similar to the entire DynamicOrderDescriptor. The struct parameter type can be combined with the array type to handle tabular data.
```cpp
*desc.add_param_desc() =
param_array("Step Table",
param_struct("", {
param_uint32("Market Quantity"),
param_uint32("Order Quantity")
}).param_type());
```
@@ -0,0 +1,69 @@
+++
title = "Subscriptions"
weight = 20
+++
An Algo exists to observe changes in the market and respond to them. When the Algo is [launched](1/server/ref/initialization/#launch-launch-attached) it uses IAlgoServices to subscribe to the events it needs to operate. Each subscribe call is paired with a matching unsubscribe call, which takes the same argument to unsubscribe.
# Book
Subscribe to book updates for the specified security call use subscribe_book and unsubscribe book.
```cpp
// Subscribe to book updates for the specified security
void IAlgoServices::subscribe_book(SecurityKey);
void IAlgoServices::unsubscribe_book(SecurityKey);
// You implement
virtual void on_book(SecurityKey, Book const &) override;
```
Get the `SecurityKey` of the current security using:
```cpp
services.subscribe_book(SecurityKey(algo_services().security().id()));
```
If your Algo needs to subscribe to other securities, their keys must be passed in as parameters.
To get the details of a security use
```cpp
api::Security const* IBeforeLaunchAlgoServices::lookup_security(SecurityKey k) const = 0;
```
# Timer
To handle time-based logic, an Algo can subscribe to a common timer event that is invoked once every 10 milliseconds. Use the TimeStamp class from `bts_chrono.h` to efficiently handle time calculations.
```cpp
// Subscribe to a periodic 10ms timer
void IAlgoServices::subscribe_timer();
// You implement
virtual void on_timer() override;
```
# Ticker
The status callback is called when the market for this security opens, closes, or has some other state transition.
```cpp
// Subscribe to trade ticker
void IAlgoServices::subscribe_ticker(SecurityKey);
// You implement
void on_ticker(SecurityKey, TradeVector const&) override;
```
# Trading Status
The status callback is called when the market for this security opens, closes, or has some other state transition.
```cpp
// Subscribe to security trading status
void IAlgoServices::subscribe_status(SecurityKey);
// You implement
virtual void on_status(SecurityKey, co2::TradingStatus) override;
```
# Child Orders
When an Algo launches a child order, it is subscribed to the changes on that child automatically. If the Algo unsubscribes from those changes, it can re-subscribe using this method.
```cpp
// Subscribe to child order updates for the specified child order.
void IAlgoServices::subscribe_child_change(OrderKey);
// You implement
virtual void on_child_change(OrderKey, ChildState const &) override;
```
+7
View File
@@ -0,0 +1,7 @@
+++
title="Samples"
template="documentation.html"
sort_by="weight"
weight = 3
+++
+354
View File
@@ -0,0 +1,354 @@
+++
title = "Join"
weight = 10
+++
Join starts working N ticks away from the market (usually) and then watches for the opposite inside to become same side inside market; if there is then enough size on that market, it will join.
<div class="info">
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
This sample is part of the Server SDK examples included in the <a href="/server/getting-started/download/">spark_sdk.zip download</a>.
</div>
```cpp
#include "spark/lib/config/config.h"
#include "spark/lib/config/protos/system.pb.h"
#include "spark/lib/domain_model/Security.h"
#include "spark/lib/orderman/orders/server/IAlgoOrder.h"
#include "spark/lib/orderman/orders/server/IAlgoServices.h"
#include "spark/lib/plugin/SparkServices.h"
#include "spark/lib/orderman/order_factory/IOrderFactory.h"
#include "spark/lib/orderman/orderman_utils/Book.h"
#include "spark/lib/orderman/orderman_utils/orderman_utils.h"
#include "spark/lib/utils/PBUtils.h"
using namespace bts::api::orderman;
using namespace bts::orderman;
namespace bts {
namespace order_example {
// Join starts working N ticks away from the market (usually) and then
// watches for the opposite inside to become same side inside market;
// if there is then enough size on that market, it will join.
class DynamicJoin : public IAlgoOrder {
public:
DynamicJoin();
~DynamicJoin();
OrderOpResult do_before_launch(IBeforeLaunchAlgoServices &) override;
void do_launch(IAlgoServices &) override;
void do_launch_attached(IAlgoServices &, OrderKey, ChildState) override;
void do_update(api::orderman::Update const &) override;
void on_book(SecurityKey, Book const &) override;
void on_child_change(OrderKey, ChildState const &) override;
private:
enum class Status;
struct PImpl;
std::unique_ptr<PImpl> me;
IAlgoServices &algo_services() const;
void try_to_join();
};
// The three stages our algo goes through. We start by waiting to
// observe the book for our security (WAITING_FOR_MD). Once we have a
// book we use it to derive our target price and we continue to
// monitor the book to see if we should join the market
// (WAITING_TO_JOIN). Once the size and price constraints are met we
// jump to the target price (JOINED). We remain in the JOINED state
// until our order is filled or canceled.
enum class DynamicJoin::Status { WAITING_FOR_MD, WAITING_TO_JOIN, JOINED };
// All state information needed for this algo
struct DynamicJoin::PImpl {
IAlgoServices *algo_services;
Quantity min_quantity_to_join;
Status status = Status::WAITING_FOR_MD;
OrderKey child_key = null_order_key();
ChildTemplate *child_template = nullptr;
Book book_at_inception;
Book last_book;
};
DynamicJoin::DynamicJoin() : me(new PImpl()) {}
DynamicJoin::~DynamicJoin() {}
IAlgoServices &DynamicJoin::algo_services() const { return *me->algo_services; }
// This is called outside of the latency sensitive path
// once. Expensive initialization should be done here, rather than
// in do_launch()
OrderOpResult DynamicJoin::do_before_launch(IBeforeLaunchAlgoServices &serv) {
auto &def = serv.definition();
bts_assert(def.has_custom_def());
bts_assert(def.custom_def().has_dynamic());
// Validate our parameters, returning an error if we find a
// problem. If an error is returned here the order will be
// abandoned.
auto &params = def.custom_def().dynamic().order_params();
auto mqi = get_if<uint32_t>(params, "Min Quantity");
if (!mqi || mqi.value() == 0) {
return OrderOpResult{
ORDER_ERROR_INVALID_ORDER_DEFINITON,
"Min Quantity parameter must be defined and non zero"};
}
me->min_quantity_to_join = Quantity(mqi.value());
if (!serv.is_attaching()) {
// If we are not attaching, create a child template so we can
// quickly launch our child when the time comes.
// We will be sending a limit order with the same side,
// security, trader, account, etc, as this algo order, so just
// copy our definition to the child definition to start with.
auto child_def = def;
// Now add a limit order component to mark our child as a limit
// order. Limit orders do not require any extra parameters
// beyond those already inherited from this algo order
// (i.e. beyond what we obtained through serv.definition()) so
// we can just use a default constructed LimitOrderDefinition.
*child_def.mutable_custom_def()->mutable_limit() = LimitOrderDefinition{};
// Now just build the child template and cache it for future use
me->child_template = &(serv.make_child_template(child_def));
} else {
// If we are attaching to an existing order then we do not need
// to spawn a new child, so there is no need to setup a child
// template
}
// All is good, return a default constructed OrderOpResult which
// indicates success.
return {};
}
// Called in the latency sensitive path, once, when the algo is first
// launched.
void DynamicJoin::do_launch(IAlgoServices &services) {
// Cache our algo services
me->algo_services = &services;
LOG(OrderMan, Diag, "Lauching DynamicJoin k: {} ",
algo_services().order_key().value());
// Launch our child order
me->child_key =
services.launch_child(*me->child_template, algo_services().price(),
algo_services().quantity());
// Subscribe to market data
services.subscribe_book(SecurityKey(algo_services().security().id()));
}
// Called in the latency sensitive path, once, when the algo is first
// launched. In this case the algo is provided with an existing order
// it is now responsible for managing.
void DynamicJoin::do_launch_attached(IAlgoServices &services,
OrderKey attached_order, ChildState st) {
// The order was launched and attached to an existing order, with
// key 'attached_order' and current state 'st'
// Cache our algo services
me->algo_services = &services;
LOG(OrderMan, Diag,
"Lauching DynamicJoin k: {} Attached to existing order: {}",
algo_services().order_key().value(), attached_order.value());
// Cache the key of the attached order we will be managing
me->child_key = attached_order;
// Subscribe to market data
services.subscribe_book(SecurityKey(services.security().id()));
// Simulate a child change so we can update our own state to
// reflect that of the child order we attached to. From this point
// forward there is no distinction between an algo instance that
// spawned a new child order and one that attached to an existing
// order.
on_child_change(attached_order, st);
}
// Called when a human (or a supervising algo) updates a parameter for
// this algo. The implementation validates the update and depending on
// the validation outcome either applies the update or terminates the
// algo.
void DynamicJoin::do_update(api::orderman::Update const &update) {
LOG(OrderMan, Diag, "DynamicJoin k: {} receiving update: {}",
algo_services().order_key().value(), utils::pb::to_string(update));
// Validate update
if (update.quantity() == 0) {
// An invalid update has been detected so we terminate the
// algo, signaling an error. Any child orders launched by
// this algo will also be terminated.
algo_services().terminate_error("Invalid update");
return;
}
// Updates have two parts, a standard part consisting of price and
// size and present in all updates, and an optional part that is
// specific to the algo in question. Below we check for the
// existance of this optional part and validate if present.
bool has_new_min_qty = false;
if (update.has_custom()) {
auto &params = update.custom().dynamic().order_params();
auto mqi = params.find("Min Quantity");
if (mqi == params.end() || mqi->second.as_uint32() == 0) {
algo_services().terminate_error(
"Minimum quantity to join must be greater than 0");
return;
}
has_new_min_qty = true;
me->min_quantity_to_join = Quantity(mqi->second.as_uint32());
}
// Update is good, forward it to our child
Update child_update;
child_update.set_price(update.price());
child_update.set_quantity(update.quantity());
algo_services().update_child(me->child_key, child_update);
// Try to join again if conditions changed
if (me->status == Status::WAITING_TO_JOIN && has_new_min_qty)
try_to_join();
}
// Called when the book for the specified security has changed
void DynamicJoin::on_book(SecurityKey, Book const &b) {
// Cache the book, so we can reffer to it in the event of a
// parameter change that might allow us to join
me->last_book = b;
LOG(OrderMan, Diag, "DynamicJoin order {} on book. BID: {}@{} ASK: {}@{}",
algo_services().order_key().value(), b.side(api::SIDE_BUY)[0].size(),
b.side(api::SIDE_BUY)[0].price(), b.side(api::SIDE_SELL)[0].size(),
b.side(api::SIDE_SELL)[0].price());
switch (me->status) {
case Status::WAITING_FOR_MD: {
auto other_side =
securities::other_side(algo_services().definition().side());
auto &other_side_top = me->last_book.side(other_side)[0];
if (other_side_top.size() > 0) {
// First time we get the opposite side market, we will use
// this price as the target price for the join
me->status = Status::WAITING_TO_JOIN;
me->book_at_inception = b;
LOG(OrderMan, Diag,
"JoinOrder order {} receiving first book: {} Target: {}",
algo_services().order_key().value(),
me->min_quantity_to_join.value(), other_side_top.price());
try_to_join();
}
} break;
case Status::JOINED:
// Nothing to do at this point
break;
case Status::WAITING_TO_JOIN:
// Check if we reached the target and join if so
try_to_join();
break;
}
}
// Given the current book, our target price and our min quantity
// parameter, join if appropriate
void DynamicJoin::try_to_join() {
bts_assert(me->status == Status::WAITING_TO_JOIN);
auto my_side = algo_services().definition().side();
auto other_side = securities::other_side(my_side);
auto &my_side_psz = me->last_book.side(my_side)[0];
auto &opposite_at_inception_psz = me->book_at_inception.side(other_side)[0];
if (my_side_psz.size() &&
my_side_psz.size() >= me->min_quantity_to_join.value() &&
securities::is_equal_or_better(
my_side, Price(my_side_psz.price()),
Price(opposite_at_inception_psz.price()))) {
// Time to update our child to join the market
Update child_update;
child_update.set_price(my_side_psz.price());
child_update.set_quantity(algo_services().quantity().value());
algo_services().update_child(me->child_key, child_update);
me->status = Status::JOINED;
LOG(OrderMan, Diag, "DynamicJoin order {} joined: {}@{}",
algo_services().order_key().value(),
algo_services().quantity().value(), my_side_psz.price());
} else {
LOG(OrderMan, Diag,
"JoinOrder order {} still waiting to join. Order: {}@{} Top of "
"the book: {}@{} Target: {}@{}",
algo_services().order_key().value(),
algo_services().quantity().value(), algo_services().price().value(),
my_side_psz.size(), my_side_psz.price(),
me->min_quantity_to_join.value(), opposite_at_inception_psz.price());
}
}
// Our child reported a change:
void DynamicJoin::on_child_change(OrderKey, ChildState const &st) {
// Our fill quantity and price is always a reflection of our
// child's state
algo_services().update_fill_state(st.total_fills, st.last_price);
switch (st.status) {
case ChildStatus::WORKING:
// Child order is still working, nothing to do
return;
case ChildStatus::COMPLETED:
// Child order completed, we should also complete
algo_services().complete();
return;
case ChildStatus::CANCELED:
// Child order unexpectedly canceled, signal an error and
// terminate
algo_services().terminate_error("Unexpected child cancel");
return;
}
}
// This is called by the spark daemon at startup. In this call we
// describe our algo's parameters and register a factory function to
// create an instance of the algo.
extern "C" void init_spark_plugin(bts::SparkServices &serv) {
using namespace bts;
DynamicOrderDescriptor join_desc;
// Start by naming our order type
join_desc.set_dynamic_order_type("dyn join");
// Now add a single unsigned int parameter, Min Quantity, that will
// determine the minimum quantity that must exist in the book in
// order for us to join the market.
*join_desc.add_param_desc() = param_uint32("Min Quantity");
// Associate the descriptor with a builder function and register
// that with the Spark server.
auto result =
serv.register_dynamic_algo_order(
join_desc, []() { return std::make_unique<DynamicJoin>(); });
if (result != bts::AlgoRegistrationResult::SUCCESS) {
// The join_desc has errors
// Check the error log for more details
}
}
} // namespace order_example
} // namespace bts
```
+146
View File
@@ -0,0 +1,146 @@
+++
title = "Template"
weight = 5
+++
A mostly blank Algo template that can be used as a jump-start for developing a new Algo.
<div class="info">
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
This sample is part of the Server SDK examples included in the <a href="/server/getting-started/download/">spark_sdk.zip download</a>.
</div>
```cpp
#include "spark/lib/config/config.h"
#include "spark/lib/config/protos/system.pb.h"
#include "spark/lib/domain_model/Security.h"
#include "spark/lib/orderman/orders/algo/IAlgoOrder.h"
#include "spark/lib/orderman/orders/algo/IAlgoServices.h"
#include "spark/lib/plugin/SparkServices.h"
#include "spark/lib/orderman/order_factory/IOrderFactory.h"
#include "spark/lib/orderman/orderman_utils/Book.h"
#include "spark/lib/orderman/orderman_utils/orderman_utils.h"
#include "spark/lib/utils/PBUtils.h"
using namespace bts::api::orderman;
using namespace bts::orderman;
namespace bts {
namespace order_example {
// MyAlgo is a blank IAlgoOrder which you can copy when starting a new Algo
class MyAlgo : public IAlgoOrder {
public:
MyAlgo();
~MyAlgo();
OrderOpResult do_before_launch(IBeforeLaunchAlgoServices &) override;
void do_launch(IAlgoServices &) override;
void do_launch_attached(IAlgoServices &, OrderKey, ChildState) override;
void do_update(api::orderman::Update const &) override;
void on_book(SecurityKey, Book const &) override;
void on_child_change(OrderKey, ChildState const &) override;
private:
IAlgoServices* algo_services;
ChildTemplate *child_template = nullptr;
OrderKey child_key = null_order_key();
};
MyAlgo::MyAlgo() : algo_services(nullptr) {}
MyAlgo::~MyAlgo() {}
// This is called outside of the latency sensitive path.
// Expensive initialization should be done here, rather than in do_launch()
OrderOpResult MyAlgo::do_before_launch(IBeforeLaunchAlgoServices &serv) {
LOG(Sdk,Info, "MyAlgo: do_before_launch");
// If we are not attaching, create a child template so we can
// quickly launch our child when the time comes.
if (!serv.is_attaching()) {
// We will be sending a limit order with the same side,
// security, trader, account, etc, as this algo order, so just
// copy our definition to the child definition to start with.
auto child_def = serv.definition();
// Now add a limit order component to mark our child as a limit
// order. Limit orders do not require any extra parameters
// beyond those already inherited from this algo order
// (i.e. beyond what we obtained through serv.definition()) so
// we can just use a default constructed LimitOrderDefinition.
*child_def.mutable_custom_def()->mutable_limit() = LimitOrderDefinition{};
// Now just build the child template and cache it for future use
child_template = &(serv.make_child_template(child_def));
}
// Default constructed result is successful
return {};
}
// Called in the latency sensitive path, once, when the algo is first launched.
// If the Algo is attaching to an existing order do_launch_attached is called instead.
void MyAlgo::do_launch(IAlgoServices &services) {
algo_services = &services;
// Subscribe to book updates for this security
services.subscribe_book(SecurityKey(services.security().id()));
// Launch a child limit order
child_key =
services.launch_child(*child_template, services.price(), services.quantity());
LOG(Sdk,Info, "MyAlgo: do_launch");
}
// Called in the latency sensitive path, once, when the algo is first
// launched. In this case the algo is provided with an existing order
// it is now responsible for managing.
void MyAlgo::do_launch_attached(IAlgoServices &services,
OrderKey attached_order, ChildState st) {
algo_services = &services;
// Subscribe to book updates for this security
services.subscribe_book(SecurityKey(services.security().id()));
// Keep track of the child key
child_key = attached_order;
LOG(Sdk,Info, "MyAlgo: do_launch_attached");
}
// Called when a human (or a supervising algo) updates a parameter for
// this algo. The implementation validates the update and depending on
// the validation outcome either applies the update or terminates the algo.
void MyAlgo::do_update(api::orderman::Update const &update) {
}
// Called when the book for the specified security has changed
void MyAlgo::on_book(SecurityKey, Book const &b) {
}
// Our child reported a change
void MyAlgo::on_child_change(OrderKey, ChildState const &st) {
}
// This is called by the spark daemon at startup. In this call we
// describe our algo's parameters and register a factory function to
// create an instance of the algo.
extern "C" void init_spark_plugin(bts::SparkServices &serv) {
using namespace bts;
DynamicOrderDescriptor desc;
// Start by naming our order type
desc.set_dynamic_order_type("My Algo");
*desc.add_param_desc() = param_bool("Enable Feature");
*desc.add_param_desc() = param_uint32("Feature Quantity");
// Associate the descriptor with a builder function and register
// that with the Spark server.
auto result =
serv.register_dynamic_algo_order(
desc, []() { return std::make_unique<MyAlgo>(); });
if (result != bts::AlgoRegistrationResult::SUCCESS) {
// The desc has errors
// Check the error log (/sparkdata/data/logging/log) for more details
}
}
} // namespace order_example
} // namespace bts
```
+9
View File
@@ -0,0 +1,9 @@
#/bin/bash
# ../../externals/linux/bin/zola/zola build
zola.exe build
rsync -avzL public/ bts@api.bluetradesys.com:/data/sdk/public/
rm -rf ./public/
+97
View File
@@ -0,0 +1,97 @@
html, body {
font-size: 16px;
height: 100%;
}
body {
font-family: "Source Sans Pro", "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 1.6;
// from http://www.heropatterns.com
background-color: #0072a2;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%234b4b4b' fill-opacity='0.4'%3E%3Cpath opacity='.5' d='M96 95h4v1h-4v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4h-9v4h-1v-4H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15v-9H0v-1h15V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h9V0h1v15h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9h4v1h-4v9zm-1 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm9-10v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-10 0v-9h-9v9h9zm-9-10h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9zm10 0h9v-9h-9v9z'/%3E%3Cpath d='M6 5V0H5v5H0v1h5v94h1V6h94V5H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
color: $foreground;
// for sticky footer
display: flex;
flex-direction: column;
min-height: 100vh;
}
a {
color: $link-color;
text-decoration: none;
cursor: pointer;
border-bottom: 1px solid rgba(0, 124, 188, 0.25);
&:hover {
border-bottom: 1px solid $link-color;
}
&:visited {
color: $link-color;
}
// totally taken from stripe
&.button {
outline: none;
white-space: nowrap;
display: inline-block;
height: 40px;
line-height: 40px;
padding: 0 14px;
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
background: #fff;
border-radius: 4px;
font-size: 15px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .025em;
color: #191919;
text-decoration: none;
transition: all .15s ease;
border-bottom: none;
&:hover {
transform: translateY(-1px);
text-decoration: none;
box-shadow: 0 7px 14px rgba(50, 50, 93, 0.1), 0 3px 6px rgba(0, 0, 0, 0.08);
}
&:active {
background-color: #f6f9fc;
transform: translateY(1px);
}
}
&.white {
color: white;
border-bottom-color: rgba(255, 255, 255, 0.25);
&:hover {
border-bottom-color: white;
}
&:visited {
color: white;
}
}
}
pre {
padding: 1rem;
overflow: auto;
}
p code, li code {
// color: #e6e1dc;
// background-color: #383838;
color: #191919;
background-color: #f5f5f5;
white-space: pre-wrap;
padding: 3px;
border-radius: 3px;
font-size: 0.85rem;
font-family: monospace;
// box-shadow: 0 1px 3px rgba(0,0,0,.1), 0 1px 1px rgba(0,0,0,.1), 0 2px 1px -1px rgba(0,0,0,.12);
}
+96
View File
@@ -0,0 +1,96 @@
.documentation {
padding: 3rem;
display: flex;
&__sidebar {
margin-right: 2rem;
ul {
padding-left: 0;
list-style: none;
}
> ul {
> li {
margin-bottom: 1rem;
}
.documentation__sidebar__title {
font-size: 1.25rem;
font-weight: bold;
}
ul {
margin-top: 0.25rem;
li {
border-left: 1px solid $background;
padding-left: 0.75rem;
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
li.active a {
font-weight: bold;
border-bottom: 1px solid $link-color;
}
}
}
}
&__content {
width: 60%;
// Same as the anchor absolute left to not overlap
margin-left: 2rem;
h1, h2, h3, h4, h5, h6 {
.zola-anchor {
font-size: 1.25rem;
visibility: hidden;
margin-left: -2rem;
text-decoration: none;
border-bottom-color: transparent;
cursor: pointer;
}
&:hover {
.zola-anchor {
visibility: visible;
}
}
}
blockquote {
border-left: 10px solid black;
padding: 0.25rem 0.5rem;
margin-left: 0;
font-style: italic;
}
}
iframe {
width: 100%;
min-height: 400px;
}
}
@media only screen and (max-width: 1000px) {
.documentation {
flex-direction: column;
padding: 2rem;
&__content {
width: 100%;
margin-left: 0;
}
&__sidebar {
border-top: 1px solid $background;
order: 1;
margin-right: 0;
margin-top: 1rem;
}
}
}
+33
View File
@@ -0,0 +1,33 @@
header {
.header__logo {
border-bottom: none;
}
nav a {
margin-right: 2rem;
}
.header__logo {
font-size: 2rem;
font-weight: bold;
&:hover {
text-decoration: none;
}
}
}
@media only screen and (max-width: 1000px) {
header {
padding: 1rem 0;
nav {
text-align: center;
}
.header__logo {
// to force menu links to be on a line below
display: block;
}
}
}
+71
View File
@@ -0,0 +1,71 @@
.inverted-colours {
background: $foreground;
color: $background;
}
.hero {
width: 60%;
margin: 0 auto;
margin-top: 2rem;
margin-bottom: 4rem;
text-align: center;
&__tagline {
margin-bottom: 2rem;
}
}
.disabled {
opacity: 0.5;
}
.selling-points {
padding: 3rem;
&__content {
display: flex;
flex-wrap: wrap;
}
}
.selling-point {
// 2 selling points per row on desktop
width: 50%;
padding: 2rem;
padding-top: 1rem;
}
.selling-header {
width: 100%;
padding: 1rem;
padding-top: 0rem;
display: flex;
align-items: center;
justify-content: center;
img {
align-self: center;
max-width: 70%;
}
}
// and 1 on mobile
@media only screen and (max-width: 1000px) {
.hero {
width: 90%;
margin-top: 2rem;
margin-bottom: 4rem;
}
.selling-points {
padding: 2rem;
}
.selling-point {
width: 100%;
padding: 1rem;
h2 {
text-align: center;
}
}
}
+43
View File
@@ -0,0 +1,43 @@
header {
padding: 2rem 3rem;
}
.container {
max-width: 1000px;
margin: 0 auto;
}
@media only screen and (max-width: 1000px) {
.container {
max-width: 90%;
}
}
.content {
flex-grow: 1;
&--reversed {
background: $foreground;
color: $background;
}
}
.linux {
padding: 25px 15px;
background: #eff0f1;
border-radius: 5px;
border: 1px solid #0072a2;
}
.info {
padding: 25px 15px;
background: #ffffe0;
border-radius: 5px;
border: 1px solid #383838;
}
footer {
text-align: center;
padding: 2rem 3rem;
}
+447
View File
@@ -0,0 +1,447 @@
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in
* IE on Windows Phone and in iOS.
*/
html {
line-height: 1.15; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers (opinionated).
*/
body {
margin: 0;
}
/**
* Add the correct display in IE 9-.
*/
article,
aside,
footer,
header,
nav,
section {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* Add the correct display in IE 9-.
* 1. Add the correct display in IE.
*/
figcaption,
figure,
main { /* 1 */
display: block;
}
/**
* Add the correct margin in IE 8.
*/
figure {
margin: 1em 40px;
}
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* 1. Remove the gray background on active links in IE 10.
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
*/
a {
background-color: transparent; /* 1 */
-webkit-text-decoration-skip: objects; /* 2 */
}
/**
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
*/
b,
strong {
font-weight: inherit;
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font style in Android 4.3-.
*/
dfn {
font-style: italic;
}
/**
* Add the correct background and color in IE 9-.
*/
mark {
background-color: #ff0;
color: #000;
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Add the correct display in IE 9-.
*/
audio,
video {
display: inline-block;
}
/**
* Add the correct display in iOS 4-7.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Remove the border on images inside links in IE 10-.
*/
img {
border-style: none;
}
/**
* Hide the overflow in IE.
*/
svg:not(:root) {
overflow: hidden;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers (opinionated).
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: sans-serif; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
* controls in Android 4.
* 2. Correct the inability to style clickable types in iOS and Safari.
*/
button,
html [type="button"], /* 1 */
[type="reset"],
[type="submit"] {
-webkit-appearance: button; /* 2 */
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* 1. Add the correct display in IE 9-.
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Remove the default vertical scrollbar in IE.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10-.
* 2. Remove the padding in IE 10-.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in IE 9-.
* 1. Add the correct display in Edge, IE, and Firefox.
*/
details, /* 1 */
menu {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Scripting
========================================================================== */
/**
* Add the correct display in IE 9-.
*/
canvas {
display: inline-block;
}
/**
* Add the correct display in IE.
*/
template {
display: none;
}
/* Hidden
========================================================================== */
/**
* Add the correct display in IE 10-.
*/
[hidden] {
display: none;
}
+47
View File
@@ -0,0 +1,47 @@
.search-container {
display: inline-block;
position: relative;
width: 300px;
input {
width: 100%;
padding: 0.5rem;
}
}
.search-results {
display: none;
position: absolute;
background: white;
color: black;
padding: 1rem;
box-shadow: 2px 2px 2px 0 rgba(0, 0, 0, 0.5);
max-height: 500px;
overflow: auto;
width: 150%;
right: 0;
&__items {
list-style: none;
}
li {
margin-top: 1rem;
border-bottom: 1px solid #ccc;
font-size: 0.9rem;
&:first-of-type {
margin-top: 0;
}
}
&__item {
margin-bottom: 1rem;
a {
font-size: 1.2rem;
display: inline-block;
margin-bottom: 0.5rem;
}
}
}
+79
View File
@@ -0,0 +1,79 @@
.themes-container {
padding: 3rem;
width: 80%;
margin: 0 auto;
img {
max-width: 100%;
}
}
@media only screen and (max-width: 1000px) {
.themes-container {
width: 100%;
margin: 0 1rem;
}
}
.themes {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.theme {
width: 45%;
text-decoration: none;
cursor: pointer;
margin-bottom: 2rem;
border-bottom: none;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
padding: 10px;
img {
width: 100%;
height: 90%;
}
span {
display: block;
text-align: center;
font-size: 1.1rem;
}
}
}
.theme-info {
display: flex;
align-items: flex-start;
.thumb {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07);
width: 400px;
margin-right: 2rem;
}
h1, p {
margin: 0;
}
padding: 1rem;
}
@media only screen and (max-width: 1000px) {
.themes .theme {
width: 100%;
}
}
@media only screen and (max-width: 1000px) {
.theme-info {
flex-direction: column;
align-items: center;
img {
margin-bottom: 1rem;
}
}
}
+19
View File
@@ -0,0 +1,19 @@
@charset "utf-8";
@import "normalize";
*, *:before, *:after {
box-sizing: border-box;
}
$background: #191919;
$foreground: white;
$link-color: #007CBC;
@import "base";
@import "layout";
@import "header";
@import "index";
@import "docs";
@import "themes";
@import "search";
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

+2
View File
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 523.438 166.055" version="1.1" viewBox="0 0 523.44 166.06" xmlns="http://www.w3.org/2000/svg"><path d="m297.43 153.29c-18.051-6.698-91.506-40.523-160.87-72.832-69.291-32.28-134.17-62.929-134.17-62.929-2.082-0.983-2.971-3.466-1.987-5.549 0.981-2.079 3.466-2.97 5.548-1.988 0.037 0.02 16.216 7.661 41.09 19.354 24.874 11.695 58.412 27.425 93.046 43.557 69.192 32.242 143.09 66.232 160.25 72.574 20.188 7.443 37.922 12.204 80.113 12.239 30.434 0 73.407-2.559 138.44-8.568 2.288-0.211 4.319 1.474 4.531 3.765 0.208 2.29-1.478 4.324-3.771 4.536-65.152 6.014-108.31 8.602-139.2 8.605h-0.423c-42.393-1e-3 -61.964-5.092-82.59-12.764z" fill="#B3B3B3"/><path d="m45.824 145.9v-138.39h101.28c27.03 0 44.924 12.184 44.924 35.789 0 17.513-8.947 26.27-19.226 29.506 12.564 3.996 21.702 15.039 21.702 31.22 0 25.319-17.516 41.88-44.545 41.88h-104.13zm41.692-60.155v-20.37h59.774c13.707 0 20.179-4.758 20.179-16.751 0-14.658-11.613-16.943-29.507-16.943h-67.96v90.234h70.052c17.325 0 29.889-4.759 29.889-18.276 0-11.423-7.423-17.894-20.939-17.894h-61.488z" fill="#0086BF"/><path d="m149.96 153.4h-104.13v-7.502h7.501-7.501v7.502h-7.504v-153.4h108.78c14.604 0.018 27.473 3.236 37.154 10.583 9.724 7.301 15.384 19.035 15.273 32.71 0.018 10.01-2.623 18.337-7.222 24.554-1.308 1.779-2.755 3.368-4.306 4.774 2.395 1.964 4.557 4.235 6.422 6.792 4.847 6.626 7.594 15.107 7.58 24.606 0.044 14.363-5.105 27.096-14.494 35.896-9.347 8.809-22.486 13.486-37.463 13.486-0.028 1e-3 -0.058 1e-3 -0.088 1e-3zm0-15.007c12.016-0.018 21.114-3.62 27.266-9.402 6.125-5.814 9.736-14.02 9.777-24.973-0.015-6.687-1.835-11.817-4.698-15.757-2.875-3.934-6.891-6.753-11.775-8.315l-22.267-7.085c-0.322 7e-3 -0.645 0.011-0.97 0.012h-52.271v5.367h53.988c7.892 0 15.036 1.876 20.422 6.475 5.429 4.589 8.092 11.651 8.015 18.922 0.016 4.524-1.103 8.88-3.35 12.497-2.236 3.632-5.46 6.38-9.02 8.3-7.172 3.825-15.677 4.938-25.019 4.979h-77.553v-105.24h75.46c6.958 0.014 13.253 0.288 19.035 1.724 5.677 1.383 11.425 4.37 14.807 10.025 2.23 3.702 3.174 8.068 3.171 12.698-5e-3 3.663-0.489 7.129-1.729 10.368-1.045 2.753-2.714 5.301-4.853 7.329l2.154-0.677c3.906-1.243 7.213-3.358 9.68-6.692 2.445-3.351 4.276-8.156 4.297-15.657-0.111-9.936-3.399-16.094-9.377-20.786-6.028-4.645-15.62-7.52-28.046-7.501l-93.773-3e-3v123.39h96.629v-1e-3zm-72.453-23.984h62.551c5.981 0.011 11.112-0.651 14.744-1.85 3.688-1.218 5.575-2.753 6.528-4.306 0.647-1.077 1.099-2.388 1.113-4.618-0.073-4.151-1.124-6.039-2.785-7.541-1.701-1.492-5.034-2.853-10.648-2.853h-61.49v-7.501h7.501-7.501v7.501h-7.504v-35.372h67.277c4.502 0.018 7.602-0.643 9.234-1.431 1.634-0.854 2.056-1.329 2.718-2.838 0.402-1.025 0.728-2.648 0.728-4.979-0.01-2.704-0.518-4.121-1.023-4.967-0.526-0.837-1.154-1.457-2.696-2.209-3.023-1.521-9.667-2.335-18.288-2.268h-60.459v75.232z" fill="#fff"/><path d="M251.22,145.899V31.68h-52.54V7.505h129.256V31.68h-52.539v114.22H251.22z" fill="#0086BF"/><path d="m251.22 153.4v-7.499h7.501-7.501v7.499h-7.504l-2e-3 -114.22h-52.538v-39.175h144.26v39.175h-52.541v114.22h-31.678zm16.673-15.001v-114.22h52.538v-9.171h-114.25v9.171h52.542v114.22h9.171v-1e-3z" fill="#fff"/><path d="m340.11 145.9v-24.176h103.74c12.942 0 20.177-7.233 20.177-18.083 0-11.802-7.234-17.893-20.177-17.893h-63.58c-26.075 0-42.257-16.562-42.257-39.404 0-22.271 15.038-38.831 42.639-38.831h99.365v24.174h-99.365c-11.042 0-17.514 6.473-17.514 16.94 0 10.469 6.661 16.751 17.324 16.751h63.388c27.98 0 43.02 13.134 43.02 39.974 0 23.226-14.089 40.546-43.02 40.546h-103.74z" fill="#383431"/><path d="m443.85 153.4h-103.74v-7.499h7.498-7.498v7.499h-7.505v-39.176h111.25c5.118-0.02 8.116-1.385 9.849-2.984 1.71-1.622 2.774-3.8 2.823-7.597-0.071-4.45-1.162-6.342-2.67-7.727-1.55-1.385-4.646-2.668-10.002-2.668h-63.58c-14.603 0.028-27.235-4.711-36.097-13.218-8.89-8.476-13.698-20.511-13.666-33.685-0.032-12.792 4.428-24.712 13.274-33.177 8.826-8.496 21.605-13.184 36.87-13.155h106.86v39.176h-106.86c-4.11 0.028-6.327 1.125-7.658 2.411-1.313 1.309-2.315 3.29-2.354 7.027 0.043 3.691 1.042 5.592 2.354 6.89 1.338 1.278 3.562 2.338 7.469 2.36h63.388c15.081-7e-3 27.896 3.536 37.065 11.888 9.185 8.367 13.511 20.865 13.455 35.59 0.022 13.078-4.037 25.357-12.824 34.248-8.729 8.882-21.678 13.796-37.497 13.796-0.066 1e-3 -0.135 1e-3 -0.2 1e-3zm-96.246-14.999 96.246-4e-3c13.017-0.037 21.505-3.779 27.018-9.329 5.488-5.576 8.475-13.569 8.494-23.712-0.052-12.118-3.246-19.606-8.572-24.519-5.35-4.923-14.046-7.951-26.939-7.956h-63.388c-6.76 0.022-13.199-2.056-17.858-6.541-4.686-4.459-7.014-10.932-6.972-17.712-0.038-6.729 2.191-13.218 6.88-17.764 4.659-4.564 11.2-6.707 18.14-6.678h91.856v-9.174l-91.856 4e-3c-12.341 0.026-20.88 3.617-26.474 8.971-5.574 5.382-8.632 12.875-8.667 22.358 0.035 9.665 3.317 17.334 9.038 22.85 5.746 5.486 14.244 9.029 25.721 9.049h63.58c7.58 0 14.573 1.767 19.88 6.38 5.34 4.606 7.87 11.665 7.799 19.018 0.048 7.05-2.504 13.916-7.652 18.62-5.117 4.73-12.205 6.982-20.026 6.965l-96.246-6e-3v9.18h-2e-3z" fill="#fff"/><path d="m45.824 145.9v-138.39h101.27c6Line truncated

After

Width:  |  Height:  |  Size: 7.6 KiB

+180
View File
@@ -0,0 +1,180 @@
function debounce(func, wait) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function () {
timeout = null;
func.apply(context, args);
}, wait);
};
}
// Taken from mdbook
// The strategy is as follows:
// First, assign a value to each word in the document:
// Words that correspond to search terms (stemmer aware): 40
// Normal words: 2
// First word in a sentence: 8
// Then use a sliding window with a constant number of words and count the
// sum of the values of the words within the window. Then use the window that got the
// maximum sum. If there are multiple maximas, then get the last one.
// Enclose the terms in <b>.
function makeTeaser(body, terms) {
var TERM_WEIGHT = 40;
var NORMAL_WORD_WEIGHT = 2;
var FIRST_WORD_WEIGHT = 8;
var TEASER_MAX_WORDS = 30;
var stemmedTerms = terms.map(function (w) {
return elasticlunr.stemmer(w.toLowerCase());
});
var termFound = false;
var index = 0;
var weighted = []; // contains elements of ["word", weight, index_in_document]
// split in sentences, then words
var sentences = body.toLowerCase().split(". ");
for (var i in sentences) {
var words = sentences[i].split(" ");
var value = FIRST_WORD_WEIGHT;
for (var j in words) {
var word = words[j];
if (word.length > 0) {
for (var k in stemmedTerms) {
if (elasticlunr.stemmer(word).startsWith(stemmedTerms[k])) {
value = TERM_WEIGHT;
termFound = true;
}
}
weighted.push([word, value, index]);
value = NORMAL_WORD_WEIGHT;
}
index += word.length;
index += 1; // ' ' or '.' if last word in sentence
}
index += 1; // because we split at a two-char boundary '. '
}
if (weighted.length === 0) {
return body;
}
var windowWeights = [];
var windowSize = Math.min(weighted.length, TEASER_MAX_WORDS);
// We add a window with all the weights first
var curSum = 0;
for (var i = 0; i < windowSize; i++) {
curSum += weighted[i][1];
}
windowWeights.push(curSum);
for (var i = 0; i < weighted.length - windowSize; i++) {
curSum -= weighted[i][1];
curSum += weighted[i + windowSize][1];
windowWeights.push(curSum);
}
// If we didn't find the term, just pick the first window
var maxSumIndex = 0;
if (termFound) {
var maxFound = 0;
// backwards
for (var i = windowWeights.length - 1; i >= 0; i--) {
if (windowWeights[i] > maxFound) {
maxFound = windowWeights[i];
maxSumIndex = i;
}
}
}
var teaser = [];
var startIndex = weighted[maxSumIndex][2];
for (var i = maxSumIndex; i < maxSumIndex + windowSize; i++) {
var word = weighted[i];
if (startIndex < word[2]) {
// missing text from index to start of `word`
teaser.push(body.substring(startIndex, word[2]));
startIndex = word[2];
}
// add <em/> around search terms
if (word[1] === TERM_WEIGHT) {
teaser.push("<b>");
}
startIndex = word[2] + word[0].length;
teaser.push(body.substring(word[2], startIndex));
if (word[1] === TERM_WEIGHT) {
teaser.push("</b>");
}
}
teaser.push("…");
return teaser.join("");
}
function formatSearchResultItem(item, terms) {
return '<div class="search-results__item">'
+ `<a href="${item.ref}">${item.doc.title}</a>`
+ `<div>${makeTeaser(item.doc.body, terms)}</div>`
+ '</div>';
}
function initSearch() {
var $searchInput = document.getElementById("search");
var $searchResults = document.querySelector(".search-results");
var $searchResultsItems = document.querySelector(".search-results__items");
var MAX_ITEMS = 10;
var options = {
bool: "AND",
fields: {
title: {boost: 2},
body: {boost: 1},
}
};
var currentTerm = "";
var index = elasticlunr.Index.load(window.searchIndex);
$searchInput.addEventListener("keyup", debounce(function() {
var term = $searchInput.value.trim();
if (term === currentTerm || !index) {
return;
}
$searchResults.style.display = term === "" ? "none" : "block";
$searchResultsItems.innerHTML = "";
if (term === "") {
return;
}
var results = index.search(term, options);
if (results.length === 0) {
$searchResults.style.display = "none";
return;
}
currentTerm = term;
for (var i = 0; i < Math.min(results.length, MAX_ITEMS); i++) {
var item = document.createElement("li");
item.innerHTML = formatSearchResultItem(results[i], term.split(" "));
$searchResultsItems.appendChild(item);
}
}, 150));
}
if (document.readyState === "complete" ||
(document.readyState !== "loading" && !document.documentElement.doScroll)
) {
initSearch();
} else {
document.addEventListener("DOMContentLoaded", initSearch);
}
+31
View File
@@ -0,0 +1,31 @@
{% extends "index.html" %}
{% block extra_nav_class %}{% endblock extra_nav_class %}
{% block extra_content_class %}content--reversed{% endblock extra_content_class %}
{% block content %}
{% set section = get_section(path="client/_index.md") %}
<div class="documentation">
<aside class="documentation__sidebar">
<ul>
{% for p in section.subsections %}
{% set subsection = get_section(path=p) %}
<li>
<span class="documentation__sidebar__title">{{ subsection.title }}</span>
<ul>
{% for page in subsection.pages %}
<li class="{% if current_path == page.path %}active{% endif %}">
<a href="{{page.permalink}}">{{page.title}}</a>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</aside>
<div class="documentation__content">
{% block doc_content %}
{% endblock doc_content %}
</div>
</div>
{% endblock content %}
+36
View File
@@ -0,0 +1,36 @@
{% extends "index.html" %}
{% block extra_nav_class %}{% endblock extra_nav_class %}
{% block extra_content_class %}content--reversed{% endblock extra_content_class %}
{% block content %}
{%if page.extra.section %}
{% set section = get_section(path="{{page.extra.section}}/_index.md") %}
{% else %}
{% set section = get_section(path="server/_index.md") %}
{% endif %}
<div class="documentation">
<aside class="documentation__sidebar">
<ul>
{% for p in section.subsections %}
{% set subsection = get_section(path=p) %}
<li>
<span class="documentation__sidebar__title">{{ subsection.title }}</span>
<ul>
{% for page in subsection.pages %}
<li class="{% if current_path == page.path %}active{% endif %}">
<a href="{{page.permalink}}">{{page.title}}</a>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</aside>
<div class="documentation__content">
{% block doc_content %}
{% endblock doc_content %}
{% block next_link %} {% endblock next_link %}
</div>
</div>
{% endblock content %}
+101
View File
@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="en-gb">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="apple-mobile-web-app-capable" content="yes">
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600" rel="stylesheet" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="{% block description %}{{ config.description }}{% endblock description %}">
<meta name="keywords" content="Futures, Options, Derivatives, Trade, Trading, Professional, options trading, futures trading, Software, API, SDK" />
<meta name="rights" content="© Blue Trading Systems" />
<meta name="author" content="{{ config.extra.author }}">
<title>{% block title %}{{ config.title }}{% endblock title %}</title>
<link rel="stylesheet" href="{{ get_url(path="site.css") }}"/>
<link rel="icon" href="{{ get_url(path="favicon.ico") }}">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<header>
<nav class="{% block extra_nav_class %}container{% endblock extra_nav_class %}">
<a class="header__logo white" href="{{ config.base_url }}">
<img width="100" src="/images/logo.svg">
</a>
<a class="white" href="{{ get_url(path="@/server/_index.md") }}" class="nav-link">Server SDK</a>
<a class="white" href="{{ get_url(path="@/client/_index.md") }}" class="nav-link">Client SDK</a>
<a class="white" href="https://www.bluetradingsystems.com/bts-spark" class="nav-link">About Spark</a>
<div class="search-container">
<input id="search" type="search" placeholder="🔎 Search">
<div class="search-results">
<div class="search-results__items"></div>
</div>
</div>
</nav>
</header>
<div class="content {% block extra_content_class %}{% endblock extra_content_class %}">
{% block content %}
<div class="hero">
<h1>Spark SDK</h1>
<p class="hero__tagline">
Spark consists of a client UI
(<a class="white" href="https://www.bluetradingsystems.com/bts-spark#ladder-algo-screen">Spark Client</a>),
a high-performance professional futures front end, connected via our proprietary protocol over TCP to our Spark Server, which in turn connects to execution venues via their native protocols.
Use the Spark SDK to extend Spark Server with your custom Algos, then use the Client SDK to launch and control them.
</p>
</div>
<div class="inverted-colours selling-points">
<div class="selling-points__content container">
<div class="selling-header">
<img src="/images/API.png" width="100%" />
</div>
<div class="selling-point">
<h2>
Server SDK
<i class="fa fa-tachometer" aria-hidden="true"></i>
</h2>
<p>
Leverage the ultra-low latency Spark C++ API to develop and run your custom Algo. Have your first sub-10 microsecond trading algorithm running in under an hour.
</p>
<a href="{{ get_url(path="@/server/_index.md") }}" class="button">Get started</a>
</div>
<div class="selling-point disabled">
<h2>
Client SDK
<i class="fa fa-gamepad" aria-hidden="true"></i>
</h2>
<p>
The Spark client SDK allows you to integrate spark with your existing ecosystem. The Spark Client is built entirely on this simple, powerful API.
</p>
<a href="" class="button" disabled>Get started</a>
</div>
<!-- <div class="selling-point disabled">
<h2>
Microsoft Excel
<i class="fa fa-table" aria-hidden="true"></i>
</h2>
<p>
More of your business is built on excel than probably should be. Continue this worrying trend with the Spark Excel API.
</p>
<a href="" class="button" disabled>Get started</a>
</div> -->
</div>
</div>
{% endblock content %}
</div>
<footer>
© Blue Trading Systems
</footer>
<script type="text/javascript" src="{{ get_url(path="elasticlunr.min.js") }}"></script>
<script type="text/javascript" src="{{ get_url(path="search_index.en.js") }}"></script>
<script type="text/javascript" src="{{ get_url(path="search.js") }}"></script>
</body>
</html>
+25
View File
@@ -0,0 +1,25 @@
{% extends "documentation.html" %}
{% block title %}{{ page.title }} | {{ super() }} {% endblock title %}
{% block doc_content %}
<h1>{{page.title}}</h1>
{{page.content | safe}}
{% endblock doc_content %}
{% block next_link %}
<p>
{% if page.lighter %}
<a href="{{ page.lighter.permalink }}">
<i class="fa fa-chevron-left fa-fw" aria-hidden="true"></i>
Previous
</a>
{% endif %}
&nbsp;
{% if page.heavier %}
<a href="{{ page.heavier.permalink }}">
Next
<i class="fa fa-chevron-right fa-fw" aria-hidden="true"></i>
</a>
{% endif %}
</p>
{% endblock next_link %}
@@ -0,0 +1,15 @@
<pre
{% if background %}
style="background-color:{{background}};"
{% else %}
style="background-color:#383838;"
{% endif %}
>
<span
{% if color %}
style="color:{{color}};"
{% else %}
style="color:#e6e1dc;"
{% endif %}
><a onclick="navigator.clipboard.writeText('{{body}}')"><i class="fa fa-clipboard fa-underline" style="color: white; text-decoration: none;"></i></a> {{body}}</span>
</pre>
@@ -0,0 +1,7 @@
{% for asset in page.assets -%}
{%- if asset is matching("[.](jpg|png)$") -%}
<a href="{{ get_url(path=asset) | safe }}" target="_blank">
<img src="{{ resize_image(path=asset, width=240, height=180, op="fill", format="auto") | safe }}" />
</a>
{%- endif %}
{%- endfor %}
+4
View File
@@ -0,0 +1,4 @@
<div class="info">
<i class="fa fa-lightbulb-o fa-fw" aria-hidden="true"></i>
{{body}}
</div>
+4
View File
@@ -0,0 +1,4 @@
<div class="linux">
<i class="fa fa-linux fa-fw" aria-hidden="true"></i>
{{body}}
</div>
@@ -0,0 +1 @@
<img src="{{ resize_image(path=path, width=width, height=height, op=op) }}" />
+11
View File
@@ -4,6 +4,17 @@ weight = 3
sort_by = "weight"
insert_anchor_links = "right"
+++
## 2.14.0
### User Visible Changes
- All ladders can now be recentered by (shift or alt) + double clicking over the Price column in a ladder
- Added a Max Order Quantity setting to the Safety Checks tab on the Ladder settings. This setting allows for a user-defined maximum order quantity.
- Added a Price Display Format setting to the Market Price and Size Display tab on the Ladder settings. This setting allows for price levels in the ladder to be displayed without a decimal separator.
- Synthetic instrument creation with 3 legs no longer defaults to butterfly quantites
### Bug Fixes
- Fixed an issue where market transition were not observed by IAlgoOrder
- Fixed a bug in error reporting
- Fixed a bug in the PnL window where specifying a certain grouping order would lead to a UI failure
## 2.13.0
### User Visible Changes
- Added the name of the spreader to the parent algo badge (for spreader child orders), in the fills, orderbook and floating orderbook windows
+4
View File
@@ -1,3 +1,7 @@
2.14.0
- Load Algos in libspark.so automatically (no symlink needed)
- Specify commands to run when sparkd starts. These will automatically be killed when sparkd terminates if they are still running.
1.5.7
- Fixed Aggressor coloring and ladder high/low coloring in SIM
+51
View File
@@ -23,7 +23,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\sp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_excel", "src\client\spark_excel\spark_excel.csproj", "{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_fix", "src\client\spark_fix\spark_fix.csproj", "{D8031C13-7BEA-430A-BB60-40927D15CFC3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_historical", "src\client\spark_historical\spark_historical.csproj", "{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}"
EndProject
Global
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
@@ -219,6 +226,50 @@ Global
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|x64.Build.0 = Release|x64
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|x86.Build.0 = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Debug|Any CPU.ActiveCfg = Debug|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Debug|x64.ActiveCfg = Debug|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Debug|x64.Build.0 = Debug|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Debug|x86.ActiveCfg = Debug|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|Any CPU.Build.0 = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|x64.ActiveCfg = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|x64.Build.0 = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|x86.ActiveCfg = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.MinSizeRel|x86.Build.0 = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Release|Any CPU.ActiveCfg = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Release|x64.ActiveCfg = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Release|x64.Build.0 = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.Release|x86.ActiveCfg = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|x64.Build.0 = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|x86.ActiveCfg = Release|x64
{D8031C13-7BEA-430A-BB60-40927D15CFC3}.RelWithDebInfo|x86.Build.0 = Release|x64
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Debug|x64.ActiveCfg = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Debug|x64.Build.0 = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Debug|x86.ActiveCfg = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Debug|x86.Build.0 = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.MinSizeRel|x64.Build.0 = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.MinSizeRel|x86.Build.0 = Debug|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Release|Any CPU.Build.0 = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Release|x64.ActiveCfg = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Release|x64.Build.0 = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Release|x86.ActiveCfg = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.Release|x86.Build.0 = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
{5F64A360-43F4-4AD8-8B04-3C3F4424BCBC}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+123
View File
@@ -0,0 +1,123 @@
drop table if exists msgs ;
create table msgs (
MsgID Int4,
TradeDate varchar,
SeqNum Int4,
SendingTime varchar,
TransactTime varchar,
MatchEventIndicator varchar,
NoMDEntries Int2,
NoOrderIDEntries Int2,
SendingTime_UnixTS Int8,
TransactTime_UnixTS Int8
);
drop table if exists books ;
create table books (
MsgID Int4,
SendingTime varchar,
TransactTime varchar,
SeqNum Int4,
bid_p_0 Real,
bid_sz_0 Int4,
bid_p_1 Real,
bid_sz_1 Int4,
bid_p_2 Real,
bid_sz_2 Int4,
bid_p_3 Real,
bid_sz_3 Int4,
bid_p_4 Real,
bid_sz_4 Int4,
bid_p_5 Real,
bid_sz_5 Int4,
bid_p_6 Real,
bid_sz_6 Int4,
bid_p_7 Real,
bid_sz_7 Int4,
bid_p_8 Real,
bid_sz_8 Int4,
bid_p_9 Real,
bid_sz_9 Int4,
Symbol Varchar,
ask_p_0 Real,
ask_sz_0 Int4,
ask_p_1 Real,
ask_sz_1 Int4,
ask_p_2 Real,
ask_sz_2 Int4,
ask_p_3 Real,
ask_sz_3 Int4,
ask_p_4 Real,
ask_sz_4 Int4,
ask_p_5 Real,
ask_sz_5 Int4,
ask_p_6 Real,
ask_sz_6 Int4,
ask_p_7 Real,
ask_sz_7 Int4,
ask_p_8 Real,
ask_sz_8 Int4,
ask_p_9 Real,
ask_sz_9 Int4,
SendingTime_UnixTS Int8,
TransactTime_UnixTS Int8
);
drop table if exists trades;
create table trades (
MsgID Int4,
Symbol varchar,
SendingTime varchar,
TransactTime varchar,
TradeDate varchar,
MDEntryPx Real,
MDnetrySize Int4,
NumberOfOrders Int4,
AgressorSide Int4,
MDTradeEntryID Int4,
AgressorOID varchar,
RestingOID varchar,
PartialQty Int4,
SendingTime_UnixTS Int8,
TransactTime_UnixTS Int8
);
drop table if exists orders;
create table orders (
MsgID Int4,
Symbol varchar,
SendingTime varchar,
TransactTime varchar,
MDEntryPx Real,
OrderID varchar,
MDDisplayQty Int4,
MDOrderPriority Int8,
OrderUpdateAction Int4,
Side Int4,
SendingTime_UnixTS Int8,
TransactTime_UnixTS Int8
);
-- create unique index msg_msg_id on msgs msgid;
-- create view ranges as (
-- select
-- sendingtime,
-- transacttime,
-- bid_p_0 price,
-- case when lag(bid_p_0) over (order by SendingTime) = bid_p_0 then null else 1 end seq
-- from
-- u0v0_books);
-- create view groups as (
-- select
-- sendingtime,
-- transacttime,
-- price,
-- sum(seq) over (order by SendingTime) grp
-- from
-- ranges);
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
DB=$1
TABLE=$2
FILE=$3
zcat $FILE | psql -U postgres -d $DB -c "copy $TABLE from STDIN with delimiter as ',' CSV HEADER"
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
docker exec -it postgres psql -U postgres "$@"
+12
View File
@@ -0,0 +1,12 @@
#!/bin/bash
#docker run --net host -e PGADMIN_DEFAULT_EMAIL=bts -e PGADMIN_DEFAULT_PASSWORD=BT5u53r dpage/pgadmin4
docker run \
--rm \
-d \
-p 8000:80 \
-e PGADMIN_DEFAULT_EMAIL=bts \
-e PGADMIN_DEFAULT_PASSWORD=BT5u53r \
--name pgadmin \
dpage/pgadmin4
+24
View File
@@ -0,0 +1,24 @@
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SRC_ROOT=$DIR/../../..
DATA_DIR=`readlink -f $SRC_ROOT/analysis_data`
DB_DIR=$DATA_DIR/db
mkdir -p $DB_DIR
docker run \
--rm \
-d \
--name postgres \
--net host \
-v $DB_DIR:/var/lib/postgresql/data \
-v /home/$USER:/home/$USER \
-v $DATA_DIR:$DATA_DIR \
-v /etc/group:/etc/group \
-v /run/user/:/run/user/ \
-u $UID \
-t postgres \
postgres
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SRC_ROOT=$DIR/../../
DATE=$1
DB=md_$DATE
$DIR/db/psql.sh -c "drop database if exists $DB"
$DIR/db/psql.sh -c "create database $DB"
$DIR/db/psql.sh -d md_$DATE -f $DIR/db/create_db.sql
PROCESSED_DATA=$SRC_ROOT/analysis_data/processed/$DATE
ALL_COMMANDS=""
for TABLE in trades orders msgs books
do
for ITEM in $PROCESSED_DATA/*.$TABLE.gz
do
ALL_COMMANDS+="docker exec -t postgres /bin/bash -c \""
ALL_COMMANDS+="$DIR/db/import_csv.sh $DB $TABLE $ITEM"
ALL_COMMANDS+="\"\n"
done
done
echo -e $ALL_COMMANDS | parallel --will-cite
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DATE=$1
SRC_ROOT=$DIR/../../
SPARK_BIN_ROOT=`readlink -f $SRC_ROOT/build`/ninja_release/server
RAW_DATA=$SRC_ROOT/analysis_data/raw/$DATE
PROCESSED_DATA=$SRC_ROOT/analysis_data/processed/$DATE
mkdir -p $PROCESSED_DATA
rm $PROCESSED_DATA/* >/dev/null
ALL_COMMANDS=""
for IN_PATH in $RAW_DATA/*.gz
do
BASE_NAME=`basename $IN_PATH`
BASE_NAME_STEM=${BASE_NAME%.*}
for CMD in trades orders msgs books
do
OUT_PATH=$PROCESSED_DATA/$BASE_NAME_STEM.$CMD.gz
ALL_COMMANDS+="(cd $SPARK_BIN_ROOT && zcat $IN_PATH | ./sparkd parsehistoricalfix $CMD | gzip >$OUT_PATH)\n"
done
done
echo -e $ALL_COMMANDS | parallel --will-cite
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
d=$1
end=${2-`date +%Y%m%d`}
until [[ $d > $end ]]; do
echo "$d"
d=$(date -d "$d + 1 day" +%Y%m%d)
done
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DATE=${1-`date -d "yesterday" +%Y%m%d`}
$DIR/sync.sh $DATE &&
$DIR/parse.sh $DATE &&
$DIR/load.sh $DATE
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DATE=$1
SRC_ROOT=$DIR/../../
RAW_DATA_ROOT=$SRC_ROOT/analysis_data/raw/$DATE
mkdir -p $RAW_DATA_ROOT
AWS_ACCESS_KEY_ID=AKIAIFIGOOWGBLEMO3PQ AWS_SECRET_ACCESS_KEY=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 AWS_REGION=us-east-1 aws s3 sync s3://cme-bts-datamine/mbo/mbo/$DATE/ $RAW_DATA_ROOT
+19
View File
@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.5)
project(spark_client)
include(${CMAKE_SOURCE_DIR}/tools/safe_dep_glob.cmake)
file(GLOB_RECURSE spark_client_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cs)
file(GLOB_RECURSE spark_client_csproj RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.csproj)
file(GLOB_RECURSE spark_ui_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} spark/*.cs)
file(GLOB_RECURSE spark_ui_csproj RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} spark/*.csproj)
list(REMOVE_ITEM spark_ui_sources ${spark_client_sources} )
list(REMOVE_ITEM spark_ui_csproj ${spark_client_csproj} )
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/../
COMMAND /bin/bash ${CMAKE_CURRENT_SOURCE_DIR}/build_spark_dotnetcore.sh
ARGS ${CMAKE_BUILD_TYPE} ${CMAKE_BINARY_DIR}
COMMENT "Building sparkcmd in netcore3"
DEPENDS libspark ${spark_client_sources} ${spark_client_csproj} ${CMAKE_CURRENT_SOURCE_DIR}/build_spark_dotnetcore.sh)
add_custom_target(spark_client_dir ALL DEPENDS ${CMAKE_BINARY_DIR}/../)
@@ -5,6 +5,7 @@
<SparkRoot>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\..))</SparkRoot>
<SourceRoot>$([System.IO.Path]::GetFullPath($(SparkRoot)\src))</SourceRoot>
<Externals>$(SparkRoot)\externals\windows</Externals>
<Externals Condition=" '$(OS)' != 'Windows_NT' ">$(SparkRoot)/externals/linux</Externals>
<DepotName>$([System.IO.Path]::GetFileName($([System.IO.Path]::GetFullPath($(SparkRoot)))))</DepotName>
<ErrorReport>None</ErrorReport>
<Prefer32Bit>False</Prefer32Bit>
@@ -22,17 +23,20 @@
<GenDir>$(BaseOutputPath)\gen\$(MSBuildProjectName)</GenDir>
</PropertyGroup>
<Import Project="$(ComputerSpecificConfig)" Condition="Exists($(ComputerSpecificConfig))" />
<ItemGroup>
<AvailableItemName Include="Proto2">
<Targets>CompileProto3</Targets>
<Targets Condition=" '$(OS)' == 'Windows_NT' " >CompileProto2</Targets>
<Targets Condition=" '$(OS)' != 'Windows_NT' " >CompileProto2Linux</Targets>
</AvailableItemName>
<AvailableItemName Include="Proto3">
<Targets>CompileProto3</Targets>
<Targets Condition=" '$(OS)' == 'Windows_NT' " >CompileProto3</Targets>
<Targets Condition=" '$(OS)' != 'Windows_NT' " >CompileProto3Linux</Targets>
</AvailableItemName>
<AvailableItemName Include="Proto3Excel">
<Targets>CompileProto3Excel</Targets>
<Targets Condition=" '$(OS)' == 'Windows_NT' ">CompileProto3Excel</Targets>
</AvailableItemName>
</ItemGroup>
@@ -43,6 +47,14 @@
<protogen>$(Externals)\bin\protogen.exe</protogen>
</PropertyGroup>
<PropertyGroup Label="ProtoBuf" Condition=" '$(OS)' != 'Windows_NT' ">
<ProtocPluginBase>$(SparkRoot)/src/lib/api/service_compiler</ProtocPluginBase>
<ProtoInclude>$(Externals)/include</ProtoInclude>
<protoc>$(Externals)/bin/protoc</protoc>
<protoc_rename>$(Externals)/bin/lowercase_files.sh</protoc_rename>
<protogen>$(Externals)/bin/protogen</protogen>
</PropertyGroup>
<ItemDefinitionGroup>
<Proto2>
</Proto2>
@@ -3,7 +3,7 @@
<Target Name="CompileProto2"
Condition="'@(Proto2)'!=''"
Condition="'@(Proto2)'!='' AND '$(OS)' == 'Windows_NT' "
Inputs="$(MSBuildProjectFile);$(protogen);%(Proto2.FullPath)"
Outputs="$(GenDir)\proto2\%(Proto2.filename).cs"
AfterTargets="PreBuildEvent">
@@ -28,7 +28,7 @@
passes wipes out the additional compile includes that we add.
-->
<Target Name="CompileProto3" AfterTargets="GetAssemblyVersion"
Condition="'@(Proto3)'!=''"
Condition="'@(Proto3)'!='' AND '$(OS)' == 'Windows_NT' "
Inputs="$(protoc);
%(Proto3.Identity);$(ProtocPluginBase)\plugin.py;
$(ProtocPluginBase)\templates\c#\client.pb.cs;
@@ -58,7 +58,7 @@
</Target>
<Target Name="CompileProto3Excel" AfterTargets="GetAssemblyVersion"
Condition="'@(Proto3Excel)'!=''"
Condition="'@(Proto3Excel)'!='' AND '$(OS)' == 'Windows_NT' "
Inputs="$(protoc);
%(Proto3Excel.Identity);$(ProtocPluginBase)\plugin.py;
$(ProtocPluginBase)\templates\excel\excel.pb.cs;"
@@ -82,12 +82,74 @@
</ItemGroup>
</Target>
<Target Name="CompileProto2Linux"
Condition="'@(Proto2)'!='' AND '$(OS)' != 'Windows_NT' "
Inputs="$(MSBuildProjectFile);$(protogen);%(Proto2.FullPath)"
Outputs="$(GenDir)/proto2/%(Proto2.filename).cs"
AfterTargets="PreBuildEvent">
<PropertyGroup>
<SourceRelativeFile>$([System.String]::Copy('%(proto2.fullpath)').Replace($(SourceRoot), ''))</SourceRelativeFile>
<SourceRelativeDir>$([System.IO.Path]::GetDirectoryName($(SourceRelativeFile)))</SourceRelativeDir>
<WorkingDirectory>$(GenDir)/proto2</WorkingDirectory>
</PropertyGroup>
<MakeDir Directories="$(WorkingDirectory)" />
<Copy SourceFiles="%(Proto2.FullPath)" DestinationFolder="$(WorkingDirectory)" SkipUnchangedFiles="True" UseHardLinksIfPossible="True" />
<Error Text="protogen.exe does not exist. If you forgot to clone with externals try: git submodule update --init --recursive" Condition="!Exists($(protogen))" />
<Message Importance="High" Text="Doing Proto2 %(proto2.filename)" />
<Exec Command="PYTHONPATH=$(Externals)/python $(Protogen) %(Proto2.filename)%(proto2.extension) --csharp_out=. -I. -I$(SourceRoot) -I$(Externals)/include"
WorkingDirectory="$(WorkingDirectory)" />
<ItemGroup>
<Compile Include="$(WorkingDirectory)/%(Proto2.filename).cs" />
</ItemGroup>
</Target>
<Target Name="CompileProto3Linux" AfterTargets="GetAssemblyVersion"
Condition="'@(Proto3)'!='' AND '$(OS)' != 'Windows_NT' "
Inputs="$(protoc);
%(Proto3.Identity);$(ProtocPluginBase)/plugin.py;
$(ProtocPluginBase)/templates/c#/client.pb.cs;
$(ProtocPluginBase)/templates/c#/server.pb.cs;
$(ProtocPluginBase)/templates/c#/immutable.pb.cs;"
Outputs="%(Proto3.OutCS);%(Proto3.OutCSServer);%(Proto3.OutCSClient);%(Proto3.OutCSImmutable)">
<MakeDir Directories="%(Proto3.OutBase)" />
<MakeDir Directories="$(IntermediateOutputPath)/gen" />
<Message Importance="High" Text="Generating service %(Proto3.FileName)" />
<Exec Command="
PYTHONPATH=$(Externals)/python $(protoc) \
%(Proto3.FullPath) \
--error_format=gcc \
--proto_path=$(protoinc):$(SourceRoot) \
--plugin=&apos;protoc-gen-service=$(ProtocPluginBase)/plugin.py&apos; \
--service_out=lang=c#,strip_out_path=1:%(Proto3.OutBase) \
--csharp_out=%(CompileOptions)%(Proto3.OutBase)"
WorkingDirectory="%(relativedir)" />
<!-- <Exec Command="$(protoc_rename) %(Proto3.OutBase)" /> -->
<ItemGroup>
<Compile Include="%(Proto3.OutCS)" />
<Compile Include="%(Proto3.OutCSClient)" />
<Compile Include="%(Proto3.OutCSServer)" />
<Compile Include="%(Proto3.OutCSImmutable)" />
</ItemGroup>
</Target>
<!-- <Target Name="RenameProto3Linux" AfterTargets="CompileProto3Linux"
Condition="'@(Proto3)'!='' AND '$(OS)' != 'Windows_NT' ">
<Move SourceFiles="$(OutBase)\Apicore.cs" DestinationFiles="$(OutBase)\apicore.cs" />
<Move SourceFiles="$(OutBase)\Apioptions.cs" DestinationFiles="$(OutBase)\apioptions.cs" />
<Move SourceFiles="$(OutBase)\Co2.cs" DestinationFiles="$(OutBase)\co2.cs" />
</Target> -->
<Target Name="AfterClean" AfterTargets="Clean">
<Delete Files="%(Proto3.OutCS)" />
<Delete Files="%(Proto3.OutCSClient)" />
<Delete Files="%(Proto3.OutCSServer)" />
<Delete Files="%(Proto3.OutCSImmutable)" />
<Delete Files="$(GenDir)\proto2\*" />
<Delete Files="$(GenDir)/proto2/*" />
<Delete Files="%(Proto3Excel.OutCSExcel)" />
</Target>
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
#$1 = Debug / Release (CMAKE_BUILD_TYPE), $2 = CMAKE_BINARY_DIR
cd "$(dirname "$0")"
echo $PWD dotnet build -c $1 ./sparkcmd/
dotnet build -c $1 ./sparkcmd/
if [ "$1" == "Release" ]
then
dotnet publish -c $1 ./sparkcmd/
ln -fs $2/src/lib/libspark.so $2/../$1/bin/netcoreapp3.0/linux-x64/publish
fi
ln -fs $2/src/lib/libspark.so $2/../$1/bin/netcoreapp3.0/linux-x64
+5 -2
View File
@@ -136,8 +136,11 @@ namespace mbts.ui.shell
try {
if (argv.Contains("-multiple") || _mutex == null || _mutex.WaitOne(TimeSpan.Zero, true))
{
if(_mutex == null || _mutex.WaitOne(TimeSpan.Zero, true))
init_stunnel(argv);
if(_mutex == null || _mutex.WaitOne(TimeSpan.Zero, true)) {
if (!argv.Contains("-nostunnel")) {
init_stunnel(argv);
}
}
return base.Run();
}
else {
@@ -1,6 +1,7 @@
using bts.api;
using bts.co2;
using bts.collections;
using bts.utils.csv;
using mbts.persist;
using mbts.spark.filters;
using mbts.ui;
@@ -52,7 +53,7 @@ namespace mbts.spark {
columns.Add(new RenderTextColumn<Row, TimeAndSalesView.Columns>(col_key, r => r[col_key], filter, filter_template, r => _get_aggressor_brush(r))
{ id = col_id(col_key), Header = header, Width = width, sort_member_path = sort_member_path, horizontal_alignment = h_alignment }
);
// be sure to load GridSettings AFTER the columns collection has been populated, the grid settings manager looks columns by id to apply the appropriate settings,
// if the collection is not populated, the column settings will not be applied
grid_settings_manager = new SimpleGridSettingsManager<Row>(columns, new Dictionary<string, GridColumnSettingsFeatureFlags> { }, row_vms);
@@ -173,6 +174,19 @@ namespace mbts.spark {
}
}
public static System.Collections.Specialized.OrderedDictionary csv_ordered_properties =>
CsvHelper.create_ordering_maintainer(
typeof(TimeAndSalesVM.Row),
new string[] {
nameof(security),
nameof(time),
nameof(price),
nameof(size),
nameof(aggressor_side),
nameof(security_key),
});
public void raise_invalidated() => invalidated?.Invoke();
}
}
@@ -3,6 +3,7 @@ using bts.api;
using bts.shell;
using bts.shell.fills;
using bts.spark;
using bts.utils.csv;
using mbts.co2;
using mbts.persist;
using mbts.ui;
@@ -63,6 +64,7 @@ namespace mbts.spark {
var current_smd_source = connectable_builder.create(vm => vm.current_security_md_observable(_bus)).OnDispatcher();
var selected_secs_source = connectable_builder.create(vm => vm.selected_securities_observable()).OnDispatcher();
_commands = new SparkCommand[] {
new SparkCommandCommand("Export to csv", Icons.Export, FileDialogCommand.export_csv(() => _vm.value.row_vms.ToCsv(TimeAndSalesVM.Row.csv_ordered_properties), "TaS")),
SparkCommands.ShowLadder(SparkCommands.KeyGestures.ShowLadder).complete(current_smd_source, md => md.HasValue, ConvertUtils.ValueOrDefault),
SparkCommands.ShowOrderTicketFromSecurity(SparkCommands.KeyGestures.ShowOrderTicket).complete(current_smd_source, md => md.HasValue, ConvertUtils.ValueOrDefault),
SparkCommands.ShowFills(SparkCommands.KeyGestures.ShowFills).complete(selected_secs_source, always_true, get_fills_startup_data),
@@ -357,19 +357,13 @@ namespace mbts.spark {
if (leg_tuples.Count == 2) {
_is_setting_price_mults = true;
_price_mult_model.override_value(leg_tuples[1], -1);
} else if (leg_tuples.Count == 3) {
_is_setting_price_mults = true;
_price_mult_model.override_value(leg_tuples[1], -2);
}
}
}
void _deduce_quantities() {
if (leg_tuples.Count == 2) {
_is_setting_quantities = true;
_quantity_model.override_value(leg_tuples[1], -1);
} else if (leg_tuples.Count == 3) {
_is_setting_quantities = true;
_quantity_model.override_value(leg_tuples[1], -2);
}
}
@@ -5,6 +5,7 @@ using bts.collections;
using bts.shell.fills;
using bts.spark;
using bts.utils;
using bts.utils.csv;
using mbts.collections;
using mbts.persist;
using mbts.spark.filters;
@@ -23,6 +24,7 @@ using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using static bts.api.orderman.Fill.Types;
using static bts.shell.FillsWindowFactory;
@@ -298,6 +300,7 @@ namespace mbts.spark {
public FillStatus fill_status => _fill.FillStatus;
public string fill_key => _fill.FillKey;
public string order_key => _order.Key.ToString();
public string symbol => fill_tuple.security?.Symbol;
// Root Algo
public OrderType root_algo_order_type => _root_algo.HasValue ? _root_algo.Value.value.CustomCase : OrderType.None;
@@ -309,6 +312,28 @@ namespace mbts.spark {
public override bool Equals(object obj) => Equals(obj as Row);
public override int GetHashCode() => _fill.FillKey.GetHashCode() ^ _order.Key.GetHashCode();
public static System.Collections.Specialized.OrderedDictionary csv_ordered_properties =>
CsvHelper.create_ordering_maintainer(typeof(Row),
new string[] {
nameof(security),
nameof(symbol),
nameof(order_type),
nameof(root_algo_display_name),
nameof(side),
nameof(fill_time),
nameof(user),
nameof(account),
nameof(exchange),
nameof(time_in_force),
nameof(size),
nameof(price),
nameof(fill_kind),
nameof(fill_status),
nameof(fill_key),
nameof(order_key),
nameof(security_key)
});
public event Action invalidated;
void IRowVM.raise_invalidated() => invalidated?.Invoke();
}
@@ -3,6 +3,7 @@ using bts.api;
using bts.shell;
using bts.shell.fills;
using bts.spark;
using bts.utils.csv;
using mbts.persist;
using mbts.ui;
using mbts.ui.settings;
@@ -59,6 +60,7 @@ namespace mbts.spark {
_view = new FillsView { DataContext = _vm };
_commands = new List<SparkCommand> {
new SparkCommandCommand("Export to csv", Icons.Export, FileDialogCommand.export_csv(() => _vm.rows.ToCsv(FillsVM.Row.csv_ordered_properties), "Fills")),
// wrap the grid settings view factory in a dialogCommand here since the vm is destroyed/recreated when the security criteria changes
SparkCommands.window_settings_command(new DialogCommand(() => {
var vm = new ShellSettingsDialogVM<GridSettings, SimpleGridSettingsVM>(
@@ -249,6 +249,7 @@ namespace mbts.spark {
const double _default_order_entry_panel_width = 110.0;
const double _default_zoom_factor = 1.0;
const bool _default_show_warn_on_cross = true;
const bool _default_enforce_max_clip = false;
public static readonly IEqualityComparer<LadderSettings> profile_equality_comparer =
EqualityComparer.Create<LadderSettings>(profile_equals);
// this class is 100% mutable (there are literally 0 readonly members),
@@ -282,6 +283,7 @@ namespace mbts.spark {
use_defaults = true;
favorite_algos = new LadderFavoriteAlgosSettings(null, 2, null);
show_warn_on_cross = _default_show_warn_on_cross;
enforce_max_clip = _default_enforce_max_clip;
}
public static LadderSettings Default {
@@ -347,6 +349,8 @@ namespace mbts.spark {
zoom_factor = _default_zoom_factor,
net_change = NetChangeTerms.None,
mini_ob = new LadderMiniOrderBookSettings(bts.shell.orderbook.OrderBookStartupData.default_mini_grid.general),
max_clip = 0,
price_display_format = PriceDisplayFormat.Default,
};
rv.row_height = LadderRender.measure_row_height(rv);
return rv;
@@ -365,6 +369,13 @@ namespace mbts.spark {
Ticks
}
public enum PriceDisplayFormat {
[Description("Default")]
Default,
[Description("Integer")]
Integer
}
[ProtoMember(1)]
public double row_height { get; set; }
[ProtoMember(2)]
@@ -499,6 +510,15 @@ namespace mbts.spark {
[ProtoMember(57)]
public double left_panel_scroll_position { get; set; }
[ProtoMember(58), DefaultValue(_default_enforce_max_clip)]
public bool enforce_max_clip { get; set; }
[ProtoMember(59)]
public uint max_clip { get; set; }
[ProtoMember(60)]
public PriceDisplayFormat price_display_format { get; set; }
public void sanitize() =>
sanitize(this);
@@ -600,7 +620,10 @@ namespace mbts.spark {
a.favorite_algos == b.favorite_algos &&
a.net_change == b.net_change &&
a.show_warn_on_cross == b.show_warn_on_cross &&
a.mini_ob == b.mini_ob;
a.mini_ob == b.mini_ob &&
a.enforce_max_clip == b.enforce_max_clip &&
a.max_clip == b.max_clip &&
a.price_display_format == b.price_display_format;
public bool Equals(LadderSettings other) =>
profile_equals(this, other) &&
@@ -29,7 +29,7 @@ using TextUtils = mbts.ui.utility.text.TextUtils;
namespace mbts.spark {
class LadderSettingsVM : DisposableViewModelBase, IWindowSettingsVM<LadderSettings>, IValueFactory<LadderSettings>, IObservable<LadderSettings>, ITemplateSelectorKey {
readonly Property<LadderSettings.BadgeStyle> _badge_style;
readonly Property<uint> _alternate_order_size;
readonly Property<uint> _alternate_order_size, _max_clip;
readonly DelegateProperty<double> _row_height;
readonly UserProperty<AccountTuple?> _default_account;
readonly UserProperty<AlgoDefinitionVM> _default_algo;
@@ -41,8 +41,9 @@ namespace mbts.spark {
AlgoID? _desired_algo;
TimeInForce _default_time_in_force;
LadderSettings.NetChangeTerms _price_format;
LadderSettings.PriceDisplayFormat _price_display_format;
double _order_entry_panel_width, _zoom_factor;
bool _auto_clear, _show_warn_on_cross;
bool _auto_clear, _show_warn_on_cross, _enforce_max_clip;
LadderSettings _current;
LadderColumnSettingsVM
_orders = new OrdersColumnSettingsVM(),
@@ -91,6 +92,7 @@ namespace mbts.spark {
_alternate_order_size = backing<uint>(nameof(alternate_order_size));
_default_account = user_backing<AccountTuple?>(nameof(default_account));
_default_algo = user_backing<AlgoDefinitionVM>(nameof(default_algo));
_max_clip = backing<uint>(nameof(max_clip));
// be sure to initialize backings before this measure_row_height call
_row_height = backing(nameof(row_height), () => LadderRender.measure_row_height(get_result()));
_orders.font_size_changed += on_font_size_changed;
@@ -166,7 +168,9 @@ namespace mbts.spark {
public SimpleGridSettingsVM mini_ob { get; } = new SimpleGridSettingsVM(OrderBookGridSettingsManager.hard_column_flags);
// price format
public LadderSettings.NetChangeTerms price_format { get => _price_format; set => Set(ref _price_format, value); }
public LadderSettings.PriceDisplayFormat price_display_format { get => _price_display_format; set => Set(ref _price_display_format, value); }
public IEnumerable<LadderSettings.NetChangeTerms> price_format_options => EnumHelper.get_values<LadderSettings.NetChangeTerms>();
public IEnumerable<LadderSettings.PriceDisplayFormat> price_display_format_options => EnumHelper.get_values<LadderSettings.PriceDisplayFormat>();
// time in force
public TimeInForce default_time_in_force { get => _default_time_in_force; set => Set(ref _default_time_in_force, value); }
public IEnumerable<TimeInForce> time_in_force_options => EnumHelper.get_values_except(TimeInForce.Undefined);
@@ -182,6 +186,8 @@ namespace mbts.spark {
public double zoom_factor { get => _zoom_factor; set => Set(ref _zoom_factor, value); }
// safety checks
public bool show_warn_on_cross { get => _show_warn_on_cross; set => Set(ref _show_warn_on_cross, value); }
public bool enforce_max_clip { get => _enforce_max_clip; set => Set(ref _enforce_max_clip, value); }
public uint max_clip { get => _max_clip.Value; set => _max_clip.Value = value; }
// favorites
public FavoriteAlgosVM favorite_algos_vm { get; }
@@ -354,8 +360,11 @@ namespace mbts.spark {
_cancel_sells_visibility.show = settings.cancel_sells_visible;
_cancel_all_visibility.show = settings.cancel_all_visible;
price_format = settings.net_change;
price_display_format = settings.price_display_format;
// safety checks
show_warn_on_cross = settings.show_warn_on_cross;
enforce_max_clip = settings.enforce_max_clip;
max_clip = settings.max_clip;
}
}
@@ -428,8 +437,11 @@ namespace mbts.spark {
clone.cancel_all_visible = _cancel_all_visibility.show;
clone.zoom_slider_visible = _zoom_slider_visbility.show;
clone.net_change = price_format;
clone.price_display_format = price_display_format;
// safety checks
clone.show_warn_on_cross = show_warn_on_cross;
clone.enforce_max_clip = enforce_max_clip;
clone.max_clip = max_clip;
return clone;
}
@@ -397,6 +397,8 @@ namespace mbts.spark {
public uint volume_column_width { get => _volume_column_width.Value; set => _volume_column_width.set(value); }
public uint alternate_order_size_from_settings => current_settings.alternate_order_size;
public bool show_warn_on_cross_from_settings => current_settings.show_warn_on_cross;
public bool enforce_max_clip_from_settings => current_settings.enforce_max_clip;
public uint max_clip_from_settings => current_settings.max_clip;
internal LadderModel model => _model;
internal IObservable<LadderSettings> settings { get; }
@@ -447,6 +449,9 @@ namespace mbts.spark {
public void key_down(KeyEventArgs e) {
if (order_properties_vm == null)
return;
if (KeyboardExtensions.IsDown(Key.Space)) {
_bus?.post(SparkTags.RequestRecenterLadder, null);
}
// the ctrl modifier requirement helps avoid keyboard-input collisions w/ algo-templates popup
if (!KeyboardExtensions.IsCtrlDown()) return;
var new_algo = order_properties_vm.algo_definitions.FirstOrDefault(o => o.algo_root.key_match(e));
@@ -462,6 +467,10 @@ namespace mbts.spark {
settings_invalidated?.Invoke();
}
public void recenter_all_ladders() {
_bus?.post(SparkTags.RequestRecenterLadder, null);
}
public Task send_order_async((double price, Side? side, MouseButton button) args) {
if (order_properties_vm != null && args.button != MouseButton.Middle) {
var size_from_alternate = args.button == MouseButton.Right;
@@ -470,6 +479,10 @@ namespace mbts.spark {
size_calculator.flash_error();
} else {
uint size = size_from_alternate ? current_settings.alternate_order_size : (uint)Math.Abs(size_calculator.value ?? 0);
// enforce max clip
if (enforce_max_clip_from_settings && size > max_clip_from_settings) {
size = max_clip_from_settings;
}
return send_order_async(args.side.Value, size, args.price);
}
}
@@ -350,6 +350,17 @@ namespace mbts.spark {
}
} else if (_vm != null) {
uint size = e.ChangedButton == MouseButton.Right ? _vm.alternate_order_size_from_settings : _vm.size_calculator.value ?? 0;
// does the size violate the local max clip
if (_vm.enforce_max_clip_from_settings && size > _vm.max_clip_from_settings) {
// note this size is only used for the cross market message, not the actual order command
size = _vm.max_clip_from_settings;
// only update the calculator value when it's a standard left-click order
if (e.ChangedButton == MouseButton.Left) {
_vm.size_calculator.value = _vm.max_clip_from_settings;
}
}
// if warning enabled && (buy above opposite inside market || ask below opposite inside market)
// when 1-sided market, _get_top_price will return NaN, and so the price comparison is false
// meaning show no warning == correct
@@ -479,8 +490,14 @@ namespace mbts.spark {
protected override void OnMouseDoubleClick(MouseButtonEventArgs e) {
var column = _column_for_point(e.GetPosition(this));
if (column.column_type == ColumnType.Price)
_scroll_to_center();
if (column.column_type == ColumnType.Price) {
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift) ||
Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt)) {
_vm?.recenter_all_ladders();
} else {
_scroll_to_center();
}
}
}
#region Row Utility Methods
@@ -588,7 +605,8 @@ namespace mbts.spark {
_settings.row_height,
_price_list,
column.settings,
security.ContractSpec);
security.ContractSpec,
_settings.price_display_format);
}
break;
case ColumnType.Ask: render_market_col(_asks); break;
@@ -911,7 +929,7 @@ namespace mbts.spark {
var prev_price_list = _price_list;
_price_list = (!(_settings.net_change == LadderSettings.NetChangeTerms.None)) ?
LadderRender.render_prices(_price_vis_tup.visual, _price_vis_tup.glyph_context, _mkt_break_lines.origin, _vm.md.settlement_price, _settings.net_change == LadderSettings.NetChangeTerms.Ticks, _row_count, _settings.row_height, _settings.price_column, security.ContractSpec) :
LadderRender.render_prices(_price_vis_tup.visual, _price_vis_tup.glyph_context, _mkt_break_lines.origin, _row_count, _settings.row_height, _settings.price_column, security.ContractSpec);
LadderRender.render_prices(_price_vis_tup.visual, _price_vis_tup.glyph_context, _mkt_break_lines.origin, _row_count, _settings.row_height, _settings.price_column, security.ContractSpec, _settings.price_display_format);
_ordershost.update_settings(_price_list, _price_comparer, _settings.row_height, _settings.orders_column);
if (prev_price_list != null) {
// maintain previous visible price range if possible
@@ -40,6 +40,8 @@ namespace mbts.spark {
// Note: the orders-column has a separate "row_padding" value: Badge.DefaultMargin
// (see how it is incorporated in measure_row_height() below)
public static readonly Thickness row_padding = new Thickness(6);
const string tick_separator_period = ".";
const string tick_separator_dash = "-";
// IMPORTANT: this method ONLY WORKS if Badges use the BadgeRender.margin/border_thickness/padding values.
// TODO: elminate the dependency on BadgeRender.margin/border_thickness/padding by integrating them into settings.
@@ -52,8 +54,11 @@ namespace mbts.spark {
public static int index_of(double[] prices, double price, IComparer<double> comparer) =>
Array.BinarySearch(prices, price, comparer);
public static GlyphRun format_text(string text, int row, double row_height, LadderColumnSettings settings, GlyphContext glyph_context) =>
glyph_context.get_glyph_run(text, settings.font_size, settings.width, row_height, HorizontalAlignment.Center, 0, VerticalAlignment.Center, row * row_height, true);
public static GlyphRun format_text(string text, int row, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, LadderSettings.PriceDisplayFormat price_display_format = LadderSettings.PriceDisplayFormat.Default) =>
glyph_context.get_glyph_run(
// long term there is probably a better way to get rid of the separator, such as in the TickExtensions._format_tick
price_display_format == LadderSettings.PriceDisplayFormat.Integer ? text.Replace(tick_separator_period, string.Empty).Replace(tick_separator_dash, string.Empty) : text,
settings.font_size, settings.width, row_height, HorizontalAlignment.Center, 0, VerticalAlignment.Center, row * row_height, true);
public static double[] gen_prices(double mid, int row_count, ContractSpecificationImmutable spec) {
// require odd number
@@ -79,10 +84,10 @@ namespace mbts.spark {
result[i] = format_text(spec.format(prices[i], reference_price, format_in_tick_terms), i, row_height, settings, glyph_context));
return result;
}
public static GlyphRun[] format_prices(double[] prices, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, ContractSpecificationImmutable spec) {
public static GlyphRun[] format_prices(double[] prices, double row_height, LadderColumnSettings settings, GlyphContext glyph_context, ContractSpecificationImmutable spec, LadderSettings.PriceDisplayFormat price_display_format) {
var result = new GlyphRun[prices.Length];
Parallel.For(0, prices.Length, i =>
result[i] = format_text(spec.format(prices[i]), i, row_height, settings, glyph_context));
result[i] = format_text(spec.format(prices[i]), i, row_height, settings, glyph_context, price_display_format));
return result;
}
@@ -104,9 +109,9 @@ namespace mbts.spark {
}
public static double[] render_prices(DrawingVisual price, GlyphContext glyph_context, double mid, int row_count, double row_height,
LadderColumnSettings settings, ContractSpecificationImmutable spec) {
LadderColumnSettings settings, ContractSpecificationImmutable spec, LadderSettings.PriceDisplayFormat price_display_format) {
var dprices = gen_prices(mid, row_count, spec);
render_prices(price, glyph_context, row_count, row_height, dprices, settings, spec);
render_prices(price, glyph_context, row_count, row_height, dprices, settings, spec, price_display_format);
return dprices;
}
@@ -122,10 +127,10 @@ namespace mbts.spark {
}
}
public static void render_prices(DrawingVisual price, GlyphContext glyph_context, int row_count, double row_height, double[] dprices, LadderColumnSettings settings, ContractSpecificationImmutable spec) {
public static void render_prices(DrawingVisual price, GlyphContext glyph_context, int row_count, double row_height, double[] dprices, LadderColumnSettings settings, ContractSpecificationImmutable spec, LadderSettings.PriceDisplayFormat price_display_format) {
var foreground = settings.foreground.rgb_brush();
//var background = new SolidColorBrush(settings.background.rgb_color());
var fprices = format_prices(dprices, row_height, settings, glyph_context, spec);
var fprices = format_prices(dprices, row_height, settings, glyph_context, spec, price_display_format);
using (var dc = price.RenderOpen())
using (_draw_with_clip(dc, settings, row_height, row_count)) {
//dc.DrawRectangle(background, null, new Rect(0, 0, settings.width, row_count * row_height));
@@ -178,6 +178,14 @@
<Setter Property="VerticalAlignment" Value="Bottom"/>
</Style>
<Style x:Key="EnableDisableFeatureText" TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{StaticResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</Style.Triggers>
</Style>
<u:KeyedTemplateSelector x:Key="LadderColumnTemplateSelector">
<u:KeyedTemplateSelector.Default>
<DataTemplate>
@@ -630,7 +638,11 @@
<ColumnDefinition Width="{Binding Source={StaticResource HorizontalPush3}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<GroupBox Header="Size Display" DataContext="{Binding size_display}" Padding="4">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<GroupBox Header="Size Display" DataContext="{Binding size_display}" Padding="4" Grid.Row="0" Grid.RowSpan="2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
@@ -710,6 +722,7 @@
</GroupBox>
<GroupBox
Grid.Column="2"
Grid.Row="0"
VerticalAlignment="Top"
Header="Price Display"
Visibility="{Binding is_synthetic, Converter={StaticResource NetChangeGroupBoxIsVisibleVisibilityConverter}}"
@@ -717,6 +730,15 @@
>
<c:RadioButtonsControl ItemsSource="{Binding price_format_options}" ItemTemplate="{StaticResource EnumDescriptionTemplate}" SelectedItem="{Binding price_format}"/>
</GroupBox>
<GroupBox
Grid.Row="1"
Grid.Column="2"
VerticalAlignment="Stretch"
Header="Price Display Format"
Padding="4"
>
<c:RadioButtonsControl ItemsSource="{Binding price_display_format_options}" ItemTemplate="{StaticResource EnumDescriptionTemplate}" SelectedItem="{Binding price_display_format}"/>
</GroupBox>
</Grid>
</TabItem>
<!-- Size Presets Tab-->
@@ -991,21 +1013,45 @@
<Grid HorizontalAlignment="Left" Margin="6">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="{Binding Source={StaticResource VerticalPush1}}"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="{Binding Source={StaticResource HorizontalPush3}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox Content="Warn on Market Cross" FlowDirection="RightToLeft" IsChecked="{Binding show_warn_on_cross}">
<!-- market cross -->
<CheckBox Name="warn" Grid.Column="0" FlowDirection="RightToLeft" IsChecked="{Binding show_warn_on_cross}">
<CheckBox.Resources>
<Style TargetType="{x:Type Path}">
<Setter Property="FlowDirection" Value="LeftToRight"/>
</Style>
</CheckBox.Resources>
</CheckBox>
<TextBlock Grid.Column="1"
Style="{StaticResource EnableDisableFeatureText}"
IsEnabled="{Binding ElementName=warn, Path=IsChecked}"
Text="Warn on Market Cross" />
<!-- max order qty -->
<CheckBox Name="enforce_max_clip" Grid.Row="1" Grid.Column="0" FlowDirection="RightToLeft" IsChecked="{Binding enforce_max_clip}">
<CheckBox.Resources>
<Style TargetType="{x:Type Path}">
<Setter Property="FlowDirection" Value="LeftToRight"/>
</Style>
</CheckBox.Resources>
</CheckBox>
<TextBlock Grid.Row="1" Grid.Column="1"
Style="{StaticResource EnableDisableFeatureText}"
IsEnabled="{Binding ElementName=enforce_max_clip, Path=IsChecked}"
MinWidth="{Binding ElementName=warn, Path=ActualWidth}"
Text="Max Order Quantity"/>
<c:TickUpDownUInt Grid.Row="1" Grid.Column="2"
IsEnabled="{Binding ElementName=enforce_max_clip, Path=IsChecked}"
Value="{Binding max_clip}" />
</Grid>
</TabItem>
<TabItem Header="Mini Order Book">
@@ -4,6 +4,7 @@ using bts.api.orderman;
using bts.collections;
using bts.spark;
using bts.utils;
using bts.utils.csv;
using mbts.ui;
using mbts.ui.controls;
using System;
@@ -11,6 +12,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Reactive.Linq;
using System.Runtime.CompilerServices;
using System.Linq;
using System.Windows.Input;
using System.Windows.Media;
using Columns = mbts.spark.OrderBookGridView.ColumnKeys;
@@ -60,6 +62,35 @@ namespace mbts.spark {
public event Action<(OrderSecurityRootPair oldval, OrderSecurityRootPair newval)> updated;
public event PropertyChangedEventHandler PropertyChanged;
public static System.Collections.Specialized.OrderedDictionary csv_ordered_properties =>
CsvHelper.create_ordering_maintainer(
typeof(OrderBookRowVM),
new string[] {
nameof(security_text),
nameof(symbol),
nameof(time_created),
nameof(last_change),
nameof(user),
nameof(account),
nameof(exchange),
nameof(time_in_force),
nameof(order_type),
nameof(root_algo_display_name),
nameof(order_sub_type),
nameof(side),
nameof(quantity),
nameof(filled_quantity),
nameof(price),
nameof(avg_price),
nameof(last_price),
nameof(piq),
nameof(status),
// last message (could contains commas, so skipping)
nameof(security_key),
nameof(order_key),
nameof(parent_order_key),
});
// Core
public OrderSecurityRootPair order_tuple { get; private set; }
public OrderRecordImmutable order => order_tuple.order.order;
@@ -4,6 +4,7 @@ using bts.shell;
using bts.shell.fills;
using bts.shell.orderbook;
using bts.spark;
using bts.utils.csv;
using bts.view;
using mbts.persist;
using mbts.ui;
@@ -184,6 +185,7 @@ namespace mbts.spark {
show_grid_settings_command.group = CommandGroups.Auxiliary;
_commands = new SparkCommand[] {
new SparkCommandCommand("Export to csv", Icons.Export, FileDialogCommand.export_csv(() => _vm.rows.ToCsv(OrderBookRowVM.csv_ordered_properties), "OrderBook")),
toggle_show_right_panel_command,
attach_selected_orders_command,
detach_selected_orders_command,
@@ -1,220 +1,223 @@
using bts.collections;
using bts.utils;
using mbts;
using mbts.collections;
using mbts.expression;
using mbts.spark;
using mbts.ui;
using mbts.ui.settings;
using mbts.ui.shell;
using mbts.ui.spark;
using mbts.ui.utility;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Dynamic;
using System.Linq;
using ColumnKeys = bts.shell.pnl.PNLView.Columns;
namespace bts.shell.pnl {
class PNLSettingsVM : DisposableViewModelBase, IWindowSettingsVM<PNLSettings>, IValueFactory<PNLSettings>, IObservable<PNLSettings>, ITemplateSelectorKey {
readonly IReadOnlyDictionary<ColumnKeys, AnchorItemVM> _anchor_cache;
readonly DeferrableActionWrapper _sync_anchors;
PNLCalculationType _calculation_type;
PNLHeaderRowDisplay _header_row_display;
PNLSettings _last_loaded;
public PNLSettingsVM(PNLSettings settings) {
// init anchor cache, deferrable resync
_anchor_cache = PNLSettings.anchorable_columns.ToDictionary(k => k, k => new AnchorItemVM(this, k));
_sync_anchors = new DeferrableActionWrapper(() => {
for (int i = 0; i < anchor_items.Count; i++) {
anchor_items[i].anchor_index = i + 1;
anchor_items[i].refresh();
}
});
core_settings_vm = new SimpleGridSettingsVM(column_factory: col_settings => {
var col_vm = new PNLColumnVM(core_settings_vm, EnumHelper.parse<ColumnKeys>(col_settings.id));
col_vm.load_from(col_settings);
return col_vm;
});
core_settings_vm.selection_highlight.bind_opacity_to_alpha = true;
_dispose = Disposable.Create(
anchor_items.Subscribe((s, e) => _sync_anchors.execute()));
load(settings);
}
public IEnumerable<AnchorItemVM> anchor_item_headers => _anchor_cache.Values;
public ObservableCollection<AnchorItemVM> anchor_items { get; } = new ObservableCollection<AnchorItemVM>();
public SimpleGridSettingsVM core_settings_vm { get; }
public PNLGroupRowAppearanceVM group_row_defaults { get; } = new PNLGroupRowAppearanceVM();
public PNLCellAppearanceVM header_row_defaults { get; } = new PNLCellAppearanceVM();
public PNLCalculationType calculation_type { get => _calculation_type; set => Set(ref _calculation_type, value); }
public IEnumerable<PNLCalculationType> calculation_types => EnumHelper.get_values_except(PNLCalculationType.None, PNLCalculationType.Same, PNLCalculationType.Opposite);
public PNLHeaderRowDisplay header_row_display { get => _header_row_display; set => Set(ref _header_row_display, value); }
public IEnumerable<PNLHeaderRowDisplay> header_row_display_options => PNLSettings.header_row_display_options;
string ITemplateSelectorKey.key => GridSettingsTemplateKeys.PNL;
public PNLSettings get_result() {
var s = _last_loaded == null ? new PNLSettings() : SparkUtils.clone_proto(_last_loaded);
s.calculation_type = _calculation_type;
s.grid = core_settings_vm.create();
// move anchor cols to the left, order wrt grouping hierarchy
var new_cols = new Lazy<List<GridColumnSettings>>(() => s.grid.columns.ToList());
for (int i = 0; i < s.grid.columns.Count; i++) {
var key = s.grid.columns[i].strong_id<ColumnKeys>();
if (_anchor_cache.TryGetValue(key, out var a) && a.anchor_index.HasValue) {
// anchor index is 1 based, subtract 1 to get 0 based
int anchor_index = a.anchor_index.Value - 1;
if (anchor_index != i && anchor_index >= 0 && anchor_index < s.grid.columns.Count) {
new_cols.Value.RemoveAt(i);
new_cols.Value.Insert(anchor_index, s.grid.columns[i]);
}
using bts.collections;
using bts.utils;
using mbts;
using mbts.collections;
using mbts.expression;
using mbts.spark;
using mbts.ui;
using mbts.ui.settings;
using mbts.ui.shell;
using mbts.ui.spark;
using mbts.ui.utility;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Dynamic;
using System.Linq;
using ColumnKeys = bts.shell.pnl.PNLView.Columns;
namespace bts.shell.pnl {
class PNLSettingsVM : DisposableViewModelBase, IWindowSettingsVM<PNLSettings>, IValueFactory<PNLSettings>, IObservable<PNLSettings>, ITemplateSelectorKey {
readonly IReadOnlyDictionary<ColumnKeys, AnchorItemVM> _anchor_cache;
readonly DeferrableActionWrapper _sync_anchors;
PNLCalculationType _calculation_type;
PNLHeaderRowDisplay _header_row_display;
PNLSettings _last_loaded;
public PNLSettingsVM(PNLSettings settings) {
// init anchor cache, deferrable resync
_anchor_cache = PNLSettings.anchorable_columns.ToDictionary(k => k, k => new AnchorItemVM(this, k));
_sync_anchors = new DeferrableActionWrapper(() => {
for (int i = 0; i < anchor_items.Count; i++) {
anchor_items[i].anchor_index = i + 1;
anchor_items[i].refresh();
}
}
// rule-based animations
var trigger_anims = core_settings_vm.columns
.OfType<PNLColumnVM>()
.SelectMany(c => c.get_triggers())
.GroupBy(tup => tup.expression)
.Where(g => CoreExpressionEvaluator<PNLRowData>.validate(g.Key))
.Select(g => (
expression: g.Key,
animations: g.ToArray()))
.ToList();
var normalized_anims = trigger_anims
.Where(tup => CoreExpressionEvaluator<PNLNormalizedData>.validate(tup.expression))
.ToList();
s = s.with(anchors: anchor_items.Select(vm => vm.key),
grid: new_cols.IsValueCreated ? s.grid.with(columns: new_cols.Value) : null,
group_columns: core_settings_vm.columns.OfType<PNLColumnVM>().Select(c => {
var col_settings = c.create();
col_settings = c.group_column_vm.apply_to(col_settings);
return col_settings;
}),
header_columns: core_settings_vm.columns.OfType<PNLColumnVM>().Select(c => {
var col_settings = c.create();
col_settings = c.header_column_vm.apply_to(col_settings);
return col_settings;
}),
animations: trigger_anims.Select(
ta => new PNLAnimationTriggerData {
expression = ta.expression,
animations = Array.ConvertAll(ta.animations, t => t.row)
}),
group_header_animations: normalized_anims
.Select(
ta => new PNLAnimationTriggerData {
expression = ta.expression,
animations = Array.ConvertAll(ta.animations, t => t.group)
}),
header_row_animations: normalized_anims.Select(
ta => new PNLAnimationTriggerData {
expression = ta.expression,
animations = Array.ConvertAll(ta.animations, t => t.header)
}));
s.header_row_display = header_row_display;
s.header_cell_appearance = PNLCellAppearanceProto.from_appearance(header_row_defaults.to_appearance());
// group
var (group_cell_appearance, group_row_background_colors) = group_row_defaults.create();
s.group_cell_appearance = PNLCellAppearanceProto.from_appearance(group_cell_appearance);
s.group_background_colors.SetItems(group_row_background_colors.Select(c => c.rgb_color()));
//
return s;
}
public void load(PNLSettings value) {
_last_loaded = value;
header_row_defaults.load(value.header_cell_appearance.to_appearance());
group_row_defaults.load_from((value.group_cell_appearance.to_appearance(), value.group_background_colors.WrapSelectorRO(c => c.argb_color())));
var column_map = _map_column_data(value.grid.columns, value.animations);
var group_column_map = _map_column_data(value.group_columns, value.group_header_animations);
var header_column_map = _map_column_data(value.header_columns, value.header_row_animations);
core_settings_vm.load_from(value.grid);
for (int i = 0; i < core_settings_vm.columns.Count; i++) {
var col_vm = core_settings_vm.columns[i] as PNLColumnVM ?? throw new InvalidOperationException($"In {nameof(PNLSettingsVM)}, all columns should be of type {typeof(PNLColumnVM)}.");
var key = EnumHelper.parse<ColumnKeys>(col_vm.id);
var (col_settings, trigger_animations) = column_map[key];
var group_data = group_column_map.GetNullable(key);
var header_data = header_column_map.GetNullable(key);
col_vm.load_from(col_settings, trigger_animations, group_data?.settings, group_data?.triggers, header_data?.triggers, header_data?.settings);
}
using (_sync_anchors.defer_execution())
anchor_items.WrapSelector(a => a.key, k => _anchor_cache[k]).sync_with(value.anchors.Intersect(PNLSettings.anchorable_columns));
header_row_display = value.header_row_display;
calculation_type = value.calculation_type;
}
PNLSettings IValueFactory<PNLSettings>.create() => get_result();
void IValueFactory<PNLSettings>.load_from(PNLSettings value) => load(value);
IDisposable IObservable<PNLSettings>.Subscribe(IObserver<PNLSettings> observer) => throw new NotImplementedException();
static Dictionary<ColumnKeys, (GridColumnSettings settings, Dictionary<string, PNLAnimation> triggers)> _map_column_data(IEnumerable<GridColumnSettings> columns, IEnumerable<PNLAnimationTriggerData> triggers) {
var map = columns.ToDictionary(
c => c.strong_id<ColumnKeys>(),
c => (settings: c, triggers: new Dictionary<string, PNLAnimation>()));
foreach (var trig in triggers) {
foreach (var anim in trig.animations) {
if (map.TryGetValue(anim.column, out var col_data))
col_data.triggers[trig.expression] = anim;
}
}
return map;
}
void _append_or_remove_anchor(ColumnKeys key, bool include) {
if (!_anchor_cache.TryGetValue(key, out var vm))
throw new KeyNotFoundException($"Column key '{key}' is not anchorable (expected one of: {string.Join(", ", PNLSettings.anchorable_columns)}).");
if (vm.include == include)
return;
if (include) {
if (anchor_items.Any(a => a.key == key))
throw new InvalidOperationException($"{nameof(anchor_items)} already contains an element with key '{key}.'");
anchor_items.Add(vm);
vm.anchor_index = anchor_items.Count;
} else {
if (!anchor_items.Remove(vm))
throw new InvalidOperationException($"{nameof(anchor_items)} does not contain an element with key '{key}.'");
vm.anchor_index = null;
}
_sync_anchors.execute();
}
public class AnchorItemVM : ViewModelBase, IEquatable<AnchorItemVM> {
readonly PNLSettingsVM _owner;
int? _anchor_index;
public AnchorItemVM(PNLSettingsVM owner, ColumnKeys key) {
_owner = owner;
this.key = key;
}
public ColumnKeys key { get; }
public bool include { get => anchor_index.HasValue; set => _owner._append_or_remove_anchor(key, value); }
public int? anchor_index { get => _anchor_index; set => Set(ref _anchor_index, value); }
public void refresh() =>
RaisePropertyChanged(nameof(include), nameof(anchor_index));
public bool Equals(AnchorItemVM other) =>
other != null && key == other.key;
public override bool Equals(object obj) =>
Equals(obj as AnchorItemVM);
public override int GetHashCode() =>
key.GetHashCode();
public override string ToString() =>
EnumHelper.get_display_name(key);
}
}
});
core_settings_vm = new SimpleGridSettingsVM(column_factory: col_settings => {
var col_vm = new PNLColumnVM(core_settings_vm, EnumHelper.parse<ColumnKeys>(col_settings.id));
col_vm.load_from(col_settings);
return col_vm;
});
core_settings_vm.selection_highlight.bind_opacity_to_alpha = true;
_dispose = Disposable.Create(
anchor_items.Subscribe((s, e) => _sync_anchors.execute()));
load(settings);
}
public IEnumerable<AnchorItemVM> anchor_item_headers => _anchor_cache.Values;
public ObservableCollection<AnchorItemVM> anchor_items { get; } = new ObservableCollection<AnchorItemVM>();
public SimpleGridSettingsVM core_settings_vm { get; }
public PNLGroupRowAppearanceVM group_row_defaults { get; } = new PNLGroupRowAppearanceVM();
public PNLCellAppearanceVM header_row_defaults { get; } = new PNLCellAppearanceVM();
public PNLCalculationType calculation_type { get => _calculation_type; set => Set(ref _calculation_type, value); }
public IEnumerable<PNLCalculationType> calculation_types => EnumHelper.get_values_except(PNLCalculationType.None, PNLCalculationType.Same, PNLCalculationType.Opposite);
public PNLHeaderRowDisplay header_row_display { get => _header_row_display; set => Set(ref _header_row_display, value); }
public IEnumerable<PNLHeaderRowDisplay> header_row_display_options => PNLSettings.header_row_display_options;
string ITemplateSelectorKey.key => GridSettingsTemplateKeys.PNL;
public PNLSettings get_result() {
var s = _last_loaded == null ? new PNLSettings() : SparkUtils.clone_proto(_last_loaded);
s.calculation_type = _calculation_type;
s.grid = core_settings_vm.create();
// move anchor cols to the left, order wrt grouping hierarchy
List<GridColumnSettings> new_cols = null;
IEnumerable<GridColumnSettings> cols = s.grid.columns;
var sorted_anchors = anchor_items.OrderBy(a => a.anchor_index).ToList();
for (int i = 0; i < sorted_anchors.Count; i++) {
if (GridSettingsHelper.try_find_column(cols, sorted_anchors[i].key, out var match, out int pos) && pos != i) {
if (new_cols == null) {
new_cols = s.grid.columns.ToList();
// set cols to new_cols so subsequent position lookups
// take previous column order manipulations into account.
cols = new_cols;
}
new_cols.RemoveAt(pos);
new_cols.Insert(i, match);
}
}
// rule-based animations
var trigger_anims = core_settings_vm.columns
.OfType<PNLColumnVM>()
.SelectMany(c => c.get_triggers())
.GroupBy(tup => tup.expression)
.Where(g => CoreExpressionEvaluator<PNLRowData>.validate(g.Key))
.Select(g => (
expression: g.Key,
animations: g.ToArray()))
.ToList();
var normalized_anims = trigger_anims
.Where(tup => CoreExpressionEvaluator<PNLNormalizedData>.validate(tup.expression))
.ToList();
s = s.with(anchors: anchor_items.Select(vm => vm.key),
grid: new_cols == null ? null : s.grid.with(columns: new_cols),
group_columns: core_settings_vm.columns.OfType<PNLColumnVM>().Select(c => {
var col_settings = c.create();
col_settings = c.group_column_vm.apply_to(col_settings);
return col_settings;
}),
header_columns: core_settings_vm.columns.OfType<PNLColumnVM>().Select(c => {
var col_settings = c.create();
col_settings = c.header_column_vm.apply_to(col_settings);
return col_settings;
}),
animations: trigger_anims.Select(
ta => new PNLAnimationTriggerData {
expression = ta.expression,
animations = Array.ConvertAll(ta.animations, t => t.row)
}),
group_header_animations: normalized_anims
.Select(
ta => new PNLAnimationTriggerData {
expression = ta.expression,
animations = Array.ConvertAll(ta.animations, t => t.group)
}),
header_row_animations: normalized_anims.Select(
ta => new PNLAnimationTriggerData {
expression = ta.expression,
animations = Array.ConvertAll(ta.animations, t => t.header)
}));
s.header_row_display = header_row_display;
s.header_cell_appearance = PNLCellAppearanceProto.from_appearance(header_row_defaults.to_appearance());
// group
var (group_cell_appearance, group_row_background_colors) = group_row_defaults.create();
s.group_cell_appearance = PNLCellAppearanceProto.from_appearance(group_cell_appearance);
s.group_background_colors.SetItems(group_row_background_colors.Select(c => c.rgb_color()));
//
return s;
}
public void load(PNLSettings value) {
_last_loaded = value;
header_row_defaults.load(value.header_cell_appearance.to_appearance());
group_row_defaults.load_from((value.group_cell_appearance.to_appearance(), value.group_background_colors.WrapSelectorRO(c => c.argb_color())));
var column_map = _map_column_data(value.grid.columns, value.animations);
var group_column_map = _map_column_data(value.group_columns, value.group_header_animations);
var header_column_map = _map_column_data(value.header_columns, value.header_row_animations);
core_settings_vm.load_from(value.grid);
for (int i = 0; i < core_settings_vm.columns.Count; i++) {
var col_vm = core_settings_vm.columns[i] as PNLColumnVM ?? throw new InvalidOperationException($"In {nameof(PNLSettingsVM)}, all columns should be of type {typeof(PNLColumnVM)}.");
var key = EnumHelper.parse<ColumnKeys>(col_vm.id);
var (col_settings, trigger_animations) = column_map[key];
var group_data = group_column_map.GetNullable(key);
var header_data = header_column_map.GetNullable(key);
col_vm.load_from(col_settings, trigger_animations, group_data?.settings, group_data?.triggers, header_data?.triggers, header_data?.settings);
}
using (_sync_anchors.defer_execution())
anchor_items.WrapSelector(a => a.key, k => _anchor_cache[k]).sync_with(value.anchors.Intersect(PNLSettings.anchorable_columns));
header_row_display = value.header_row_display;
calculation_type = value.calculation_type;
}
PNLSettings IValueFactory<PNLSettings>.create() => get_result();
void IValueFactory<PNLSettings>.load_from(PNLSettings value) => load(value);
IDisposable IObservable<PNLSettings>.Subscribe(IObserver<PNLSettings> observer) => throw new NotImplementedException();
static Dictionary<ColumnKeys, (GridColumnSettings settings, Dictionary<string, PNLAnimation> triggers)> _map_column_data(IEnumerable<GridColumnSettings> columns, IEnumerable<PNLAnimationTriggerData> triggers) {
var map = columns.ToDictionary(
c => c.strong_id<ColumnKeys>(),
c => (settings: c, triggers: new Dictionary<string, PNLAnimation>()));
foreach (var trig in triggers) {
foreach (var anim in trig.animations) {
if (map.TryGetValue(anim.column, out var col_data))
col_data.triggers[trig.expression] = anim;
}
}
return map;
}
void _append_or_remove_anchor(ColumnKeys key, bool include) {
if (!_anchor_cache.TryGetValue(key, out var vm))
throw new KeyNotFoundException($"Column key '{key}' is not anchorable (expected one of: {string.Join(", ", PNLSettings.anchorable_columns)}).");
if (vm.include == include)
return;
if (include) {
if (anchor_items.Any(a => a.key == key))
throw new InvalidOperationException($"{nameof(anchor_items)} already contains an element with key '{key}.'");
anchor_items.Add(vm);
vm.anchor_index = anchor_items.Count;
} else {
if (!anchor_items.Remove(vm))
throw new InvalidOperationException($"{nameof(anchor_items)} does not contain an element with key '{key}.'");
vm.anchor_index = null;
}
_sync_anchors.execute();
}
public class AnchorItemVM : ViewModelBase, IEquatable<AnchorItemVM> {
readonly PNLSettingsVM _owner;
int? _anchor_index;
public AnchorItemVM(PNLSettingsVM owner, ColumnKeys key) {
_owner = owner;
this.key = key;
}
public ColumnKeys key { get; }
public bool include { get => anchor_index.HasValue; set => _owner._append_or_remove_anchor(key, value); }
public int? anchor_index { get => _anchor_index; set => Set(ref _anchor_index, value); }
public void refresh() =>
RaisePropertyChanged(nameof(include), nameof(anchor_index));
public bool Equals(AnchorItemVM other) =>
other != null && key == other.key;
public override bool Equals(object obj) =>
Equals(obj as AnchorItemVM);
public override int GetHashCode() =>
key.GetHashCode();
public override string ToString() =>
EnumHelper.get_display_name(key);
}
}
}
@@ -90,12 +90,11 @@ namespace bts.shell.pnl {
}
int? _try_compare_groups(CollectionViewGroup x, CollectionViewGroup y) {
if (x == null || y == null)
return null;
var xcell = (IPNLCellData)x.Name;
var ycell = (IPNLCellData)y.Name;
var comp = _get_column_comparer(xcell.column);
return comp.value_comparer.Compare(xcell.value, ycell.value);
if (x?.Name is IPNLCellData xcell && y?.Name is IPNLCellData ycell) {
var comp = _get_column_comparer(xcell.column);
return comp.value_comparer.Compare(xcell.value, ycell.value);
}
return null;
}
}
}
}
@@ -698,8 +698,8 @@
c:DataGridFilterProperties.FilterActive="{Binding DataContext.security_filter.active, Source={u:DirectReference _grid}}"
c:DataGridFilterProperties.FilterOpen="{Binding DataContext.security_filter.open, Source={u:DirectReference _grid}}"
key="Security"
sort_member_path="security_cell.cell_data"
data_member_path="security"
data_member_path="security_cell.cell_data"
sort_member_path="security"
HeaderTemplate="{StaticResource AnchorableColumnHeaderTemplate}"
/>
<!--Security Key-->
+15 -44
View File
@@ -653,54 +653,25 @@ namespace mbts.spark.utilities {
return def;
}
}
static CustomOrderDefinition.CustomOneofCase[] algo_config(
Func<bts.config.AlgoPermissions, List<string>> selector)
{
var conf = mbts.config.Configuration.get<bts.config.AlgoPermissions>();
return selector(conf).Select(x =>
{
return (CustomOrderDefinition.CustomOneofCase)System.Enum.Parse(typeof(CustomOrderDefinition.CustomOneofCase), x, true);
}).ToArray();
}
public static readonly CustomOrderDefinition.CustomOneofCase[]
// exchange_order_types are the types which can be submitted on an exchange security
exchange_order_types = new[] {
CustomOrderDefinition.CustomOneofCase.Market,
CustomOrderDefinition.CustomOneofCase.Limit,
CustomOrderDefinition.CustomOneofCase.Stop,
CustomOrderDefinition.CustomOneofCase.StopLimit,
CustomOrderDefinition.CustomOneofCase.GlbxIceberg,
CustomOrderDefinition.CustomOneofCase.Iceberg,
CustomOrderDefinition.CustomOneofCase.Lean,
CustomOrderDefinition.CustomOneofCase.Join,
CustomOrderDefinition.CustomOneofCase.Cover,
CustomOrderDefinition.CustomOneofCase.Top,
CustomOrderDefinition.CustomOneofCase.Offset,
CustomOrderDefinition.CustomOneofCase.Splitter,
CustomOrderDefinition.CustomOneofCase.Scratch,
CustomOrderDefinition.CustomOneofCase.Prorata,
},
spreader_order_types = new[] {
CustomOrderDefinition.CustomOneofCase.Spreader,
CustomOrderDefinition.CustomOneofCase.Iceberg,
CustomOrderDefinition.CustomOneofCase.Lean,
CustomOrderDefinition.CustomOneofCase.Join,
CustomOrderDefinition.CustomOneofCase.Cover,
CustomOrderDefinition.CustomOneofCase.Top,
CustomOrderDefinition.CustomOneofCase.Splitter,
CustomOrderDefinition.CustomOneofCase.Scratch,
CustomOrderDefinition.CustomOneofCase.Prorata,
},
attachable_order_types = new[] {
CustomOrderDefinition.CustomOneofCase.Iceberg,
CustomOrderDefinition.CustomOneofCase.Lean,
CustomOrderDefinition.CustomOneofCase.Join,
CustomOrderDefinition.CustomOneofCase.Cover,
CustomOrderDefinition.CustomOneofCase.Top,
CustomOrderDefinition.CustomOneofCase.Offset,
CustomOrderDefinition.CustomOneofCase.Scratch,
CustomOrderDefinition.CustomOneofCase.Prorata,
},
outright_order_types = new[] {
CustomOrderDefinition.CustomOneofCase.Market,
CustomOrderDefinition.CustomOneofCase.Limit,
CustomOrderDefinition.CustomOneofCase.Stop,
CustomOrderDefinition.CustomOneofCase.StopLimit,
CustomOrderDefinition.CustomOneofCase.GlbxIceberg,
};
exchange_order_types = algo_config(x => x.exchange_order_types),
spreader_order_types = algo_config(x => x.spreader_order_types),
attachable_order_types = algo_config(x => x.attachable_order_types),
outright_order_types = algo_config(x => x.outright_order_types);
public static readonly CustomOrderDefinition.CustomOneofCase[] all_order_types = exchange_order_types.Union(spreader_order_types).ToArray();
public static void copy_values(CustomOrderDefinitionImmutable source, ref CustomOrderDefinition target) =>
@@ -54,13 +54,16 @@ namespace mbts.spark
{
readonly Func<TModel, TView> _convert;
readonly Func<TView, TModel> _convert_back;
readonly Func<IMessage, IMessage> _message_override;
TView _value;
public GenericOrderParamVM(FieldDescriptor field_descriptor, Func<TModel, TView> convert, Func<TView, TModel> convert_back) :
public GenericOrderParamVM(FieldDescriptor field_descriptor, Func<TModel, TView> convert,
Func<TView, TModel> convert_back, Func<IMessage, IMessage> message_override = null) :
base(field_descriptor)
{
_convert = convert;
_convert_back = convert_back;
_message_override = message_override;
}
public TView value
@@ -68,7 +71,8 @@ namespace mbts.spark
get => _value;
set
{
this.descriptor.Accessor.SetValue(this.message, _convert_back(_value = value));
this.descriptor.Accessor.SetValue( _message_override == null ? this.message : _message_override(this.message),
_convert_back(_value = value));
RaisePropertyChanged();
}
}
@@ -84,7 +88,7 @@ namespace mbts.spark
protected override void on_param_changed()
{
_value = _convert(ConvertUtils.try_convert<TModel>(this.descriptor.Accessor.GetValue(this.message)));
_value = _convert(ConvertUtils.try_convert<TModel>(this.descriptor.Accessor.GetValue(_message_override == null ? this.message : _message_override(this.message))));
RaisePropertyChanged(nameof(value));
}
}
@@ -163,7 +167,6 @@ namespace mbts.spark
RaisePropertyChanged();
}
}
public IObservable<QuantityMeasureImmutable?> subscribe_value()
{
return Observable.Create<QuantityMeasureImmutable?>(o =>
@@ -174,10 +177,9 @@ namespace mbts.spark
o.OnNext(quantity);
});
}
protected override void on_param_changed()
{
RaisePropertyChanged(nameof(quantity));
}
}
}
}
@@ -96,9 +96,41 @@ namespace mbts.spark {
{
Google.Protobuf.Reflection.MessageDescriptor desc = new TMutable().Descriptor;
_parameters.SyncWithDictionary(
desc.Fields.InDeclarationOrder().Where(_is_value_param_desc).ToDictionary(p => p.Name), _mk_param_vm);
desc.Fields.InDeclarationOrder().Where(_is_value_param_desc).ToDictionary(p => p.Name), x => _mk_param_vm(x));
add_message_params(desc);
}
}
void add_message_params(Google.Protobuf.Reflection.MessageDescriptor desc)
{
var msgs = desc.Fields.InDeclarationOrder().Where(x => !_is_value_param_desc(x) &&
x.MessageType.ClrType != typeof(CustomOrderDefinition) );
foreach(var message_field in msgs)
{
foreach (var fd in message_field.MessageType.Fields.InDeclarationOrder())
{
if(_is_value_param_desc(fd)) //one level deep
{
var mk = _mk_param_vm(fd,
outside_object =>
{
var msgfield = message_field.Accessor.GetValue(outside_object);
if(msgfield == null)
{
message_field.Accessor.SetValue(outside_object, Activator.CreateInstance(message_field.MessageType.ClrType));
msgfield = message_field.Accessor.GetValue(outside_object);
}
return (IMessage)msgfield;
});
if(mk == null)
continue;
if(!_parameters.Add(mk))
_parameters.Add(message_field.Name + "_" + mk.descriptor.Name, mk);
}
}
}
}
static bool _is_value_param_desc(FieldDescriptor desc)
{
return (desc.FieldType != Google.Protobuf.Reflection.FieldType.Message ||
@@ -117,7 +149,7 @@ namespace mbts.spark {
return v;
}
GenericOrderParamVM<TMutable> _mk_param_vm(FieldDescriptor descriptor)
GenericOrderParamVM<TMutable> _mk_param_vm(FieldDescriptor descriptor, Func<IMessage, IMessage> message_override = null)
{
ExceptionAssert.Argument.NotNull(descriptor, nameof(descriptor));
@@ -134,33 +166,36 @@ namespace mbts.spark {
return pvm;
}
else if (descriptor.FieldType == FieldType.Bool)
return mk<bool?, bool>(descriptor, v => v, v => v.GetValueOrDefault());
return mk<bool?, bool>(descriptor, v => v, v => v.GetValueOrDefault(), message_override);
else if (descriptor.FieldType == FieldType.Double || descriptor.FieldType == FieldType.Float)
return mk<double, double>(descriptor, v => v, v => v, double.NaN);
return mk<double, double>(descriptor, v => v, v => v, message_override, double.NaN);
else if (descriptor.FieldType == FieldType.Int32)
return mk<int?, int>(descriptor, v => v, v => v.GetValueOrDefault());
return mk<int?, int>(descriptor, v => v, v => v.GetValueOrDefault(), message_override);
else if (descriptor.FieldType == FieldType.UInt32)
return mk<uint?, uint>(descriptor, v => v, v => v.GetValueOrDefault());
return mk<uint?, uint>(descriptor, v => v, v => v.GetValueOrDefault(), message_override);
else if (descriptor.FieldType == FieldType.String)
return mk<string, string>(descriptor, v => v, v => v);
return mk<string, string>(descriptor, v => v, v => v, message_override);
else
return null;
}
GenericOrderParamVM<TMutable, TView, TModel> mk<TView, TModel>(FieldDescriptor fdesc, Func<TModel, TView> convert, Func<TView, TModel> convert_back, TView default_value = default)
GenericOrderParamVM<TMutable, TView, TModel> mk<TView, TModel>(FieldDescriptor fdesc, Func<TModel, TView> convert, Func<TView, TModel> convert_back,
Func<IMessage, IMessage> message_override = null, TView default_value = default)
{
var pvm = new GenericOrderParamVM<TMutable, TView, TModel>(fdesc, convert, convert_back);
return attached<TView, GenericOrderParamVM<TMutable, TView, TModel>>(pvm, get_from_param, assign_to_param, default_value);
var pvm = new GenericOrderParamVM<TMutable, TView, TModel>(fdesc, convert, convert_back, message_override);
return attached<TView, GenericOrderParamVM<TMutable, TView, TModel>>(pvm, get_from_param, assign_to_param,
message_override, default_value);
TView get_from_param(IMessage param, FieldDescriptor fd) => convert(ConvertUtils.try_convert<TModel>(fdesc.Accessor.GetValue(param)));
void assign_to_param(IMessage param, FieldDescriptor fd, TView value) => fdesc.Accessor.SetValue(param, convert_back(value));
}
TParam attached<T, TParam>(TParam pvm, Func<IMessage, FieldDescriptor, T> selector, Action<IMessage, FieldDescriptor, T> assign_to_param, T default_value = default) where TParam : GenericOrderParamVM<TMutable>, IGenericOrderParamVM<T>
TParam attached<T, TParam>(TParam pvm, Func<IMessage, FieldDescriptor, T> selector, Action<IMessage, FieldDescriptor, T> assign_to_param,
Func<IMessage, IMessage> message_override = null, T default_value = default) where TParam : GenericOrderParamVM<TMutable>, IGenericOrderParamVM<T>
{
add_property<T>(
pvm.descriptor.Name,
mdef => mdef != null ? selector(mdef, pvm.descriptor) : default_value,
(mdef, v) => assign_to_param(mdef, pvm.descriptor, v),
mdef => mdef != null ? selector( message_override == null ? mdef : message_override(mdef), pvm.descriptor) : default_value,
(mdef, v) => assign_to_param(message_override == null ? mdef : message_override(mdef), pvm.descriptor, v),
() => pvm.value,
v => pvm.value = v,
pvm.subscribe_value(),
@@ -4,14 +4,14 @@ using OffsetDefi = bts.api.orderman.OffsetOrderDefinitionImmutable;
namespace mbts.spark {
static partial class OrderTypeVMFactory {
class OffsetOrderVM : OrderTypeVMBase<OffsetDef, OffsetDefi> {
readonly Property<uint?> _tick_offset_on_deploy;
readonly Property<int?> _tick_offset_on_deploy;
public OffsetOrderVM(AlgoKey key, string display_name, AlgoEditingPermissions editing_permissions)
: base(key, display_name, editing_permissions) {
_tick_offset_on_deploy = add_nullable_property(nameof(tick_offset_on_deploy), OffsetDef.TickOffsetOnDeployFieldNumber, 0u);
_tick_offset_on_deploy = add_nullable_property(nameof(tick_offset_on_deploy), OffsetDef.TickOffsetOnDeployFieldNumber, 0);
}
public uint? tick_offset_on_deploy { get => _tick_offset_on_deploy.Value; set => _tick_offset_on_deploy.set(value); }
public int? tick_offset_on_deploy { get => _tick_offset_on_deploy.Value; set => _tick_offset_on_deploy.set(value); }
}
}
}
+1 -2
View File
@@ -9,7 +9,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Configurations>Debug;Release</Configurations>
<Platforms>x64</Platforms>
<RuntimeIdentifiers>win7-x64</RuntimeIdentifiers>
<PlatformTarget>AnyCPU</PlatformTarget>
<LanguageTargets>$(MSBuildExtensionsPath)\$(VisualStudioVersion)\Bin\Microsoft.CSharp.targets</LanguageTargets>
<ApplicationIcon>logo.ico</ApplicationIcon>
@@ -35,7 +34,7 @@
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
<PackageReference Include="IronPython" Version="2.7.7" />
<PackageReference Include="NAudio" Version="1.8.4" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.8.0" />
Loaded 100 of 408 files, more files were not shown because too many files have changed in this diff. Show more