Compare commits

..
31 Commits
Author SHA1 Message Date
John Colvin b95da40fec feat: Impl synthetic book 2022-11-28 10:42:05 -05:00
John Colvin 755f841a6e refactor: Change spreader leg qty to int
The synth book computation code doesn't support doubles
2022-11-25 13:20:34 -05:00
John Colvin 2d10c94b69 chore: Make csharp code compatible with net471, lang version 7 2022-11-25 13:20:33 -05:00
John Colvin dfc5fcc16a fix build (client): Change 'WIN32' macros to '_WIN32'
Not sure exactly how this broke, but the WIN32 macro is no longer defined.
2022-11-20 14:22:42 -05:00
Taha Afzal 864e2a3edc Comments 2022-11-10 07:18:42 -05:00
Taha Afzal b9142202e0 UI code complete 2022-11-09 23:13:16 -05:00
Taha Afzal 7353a6dc3c Added get_data() to LegControl.cs 2022-11-08 23:26:10 -05:00
Taha Afzal b55eecc8b9 Eagle front end 2022-11-06 18:52:38 -05:00
Taha Afzal 3f0078d582 Added sample test 2022-05-09 23:08:59 -04:00
Taha Afzal e47186f0fd Fixing tests 2022-05-08 22:47:10 -04:00
Taha Afzal 4b92292fa1 Pushed a sample test 2022-05-04 09:31:09 -04:00
Taha Afzal 3a8125bba3 Namespace changes and moving all shared files to spreader_order directory 2022-05-02 23:27:30 -04:00
Taha Afzal 0b14bd1ca3 ChildOrder changed to bts::spreader::ChildOrder 2022-05-01 12:41:39 -04:00
Taha Afzal 63252b017b Cleaning up the moved events 2022-04-30 22:31:37 -04:00
Taha Afzal df1efb2295 Moving events to bts::spreader 2022-04-29 18:19:29 -04:00
Taha Afzal 3f37777eb9 'Moved' book and accompaying classes over 2022-04-29 00:21:34 -04:00
Taha Afzal 04629f28e8 Removing SpreaderOrder's inheritence from Order 2022-04-26 23:35:43 -04:00
Taha Afzal 47c4d8c4a7 Order is being routed to IOrderGateway 2022-04-26 00:40:17 -04:00
Taha Afzal eb87ebcfa1 Removed IAlternateOrderGateway, fixing tests now 2022-04-24 22:21:02 -04:00
Taha Afzal 195fd11e2e IOrderGateway accessor added to ISpreaderManager 2022-04-24 15:45:35 -04:00
Taha Afzal 413c24d147 Completed LegOrderRouter, which will be used by SpreaderChildOrderState to send orders 2022-04-24 01:18:58 -04:00
Taha Afzal fe4be118ee Adding LegOrderRouter 2022-04-24 00:16:09 -04:00
Taha Afzal 7ff09902b8 IOrderGateway::report_spreader_state takes an bts::integration::OrderUpdate now 2022-04-23 21:53:17 -04:00
Taha Afzal f90e41ea65 Moved the new interface, types into their own files 2022-04-20 23:58:05 -04:00
Taha Afzal ff2546da56 Adding function that returns OrderDef to ISpreaderManager 2022-04-20 21:46:45 -04:00
Taha Afzal f7426d9f0f All tests moved to use SpreaderWrapper 2022-04-18 23:43:06 -04:00
Taha Afzal 36bbcf849c More tests for SpreaderWrapper 2022-04-18 22:43:19 -04:00
Taha Afzal bd39d407aa More spreader tests pass 2022-04-17 23:57:07 -04:00
Taha Afzal 81dde8e9df Moving tests over to use SpreaderWrapper instead of SpreaderOrder 2022-04-17 18:48:51 -04:00
Taha Afzal 3f4a4fbac8 The 3 wrappers SpreaderOrderBuilder, SpreaderOrderServices and SpreaderPreActivationOrderServices do not call into the Spark infrastructure any more 2022-04-17 15:08:56 -04:00
Taha Afzal 2e6676b151 Added Spreader Wrapper 2022-04-16 23:55:39 -04:00
1815 changed files with 72388 additions and 117026 deletions

No files matched your search

-18
View File
@@ -7,24 +7,6 @@
"commands": [
"dotnet-format"
]
},
"fable": {
"version": "4.0.0-theta-018",
"commands": [
"fable"
]
},
"fantomas": {
"version": "5.2.2",
"commands": [
"fantomas"
]
},
"fake-cli": {
"version": "6.0.0",
"commands": [
"fake"
]
}
}
}
+3 -3
View File
@@ -1,6 +1,5 @@
nohup.out
build/**
install/**
build/
.build_proxy/
cmake-build-debug/
.cache/
@@ -41,6 +40,8 @@ trace_data/
.ionide/*
/.ignore
*.rej
/build
/build.*/*
.clangd/
*CMakeDeps.cmake
/sniper.ipynb
@@ -50,4 +51,3 @@ trace_data/
*.tmp/*
/.venv*/*
.cache/
src/web/api/tsconfig.*.g.json
+3
View File
@@ -7,3 +7,6 @@
[submodule "docker/windows"]
path = docker/windows
url = git@bitbucket.org:bluetradesys/windows_docker.git
[submodule "src/deribit-crypto-connector-demo-application"]
path = src/deribit-crypto-connector-demo-application
url = git@gitlab.com:cryptoexchanges1/deribit-crypto-connector-demo-application.git
+3 -22
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.5)
project(spark)
if(WIN32)
@@ -7,18 +7,12 @@ else()
set(platform "linux")
endif()
set(
EXTERNALS_ROOT
"${CMAKE_SOURCE_DIR}/externals/${platform}"
CACHE
STRING
"External dependencies root folder (should contain folders: lib, bin, include")
set(EXTERNALS_ROOT "${CMAKE_SOURCE_DIR}/externals/${platform}")
set(SPARK_PYTHON "${EXTERNALS_ROOT}/python")
set(SPARK_BIN "${EXTERNALS_ROOT}/bin")
set(SPARK_INCLUDE "${EXTERNALS_ROOT}/include")
set(SPARK_LIB "${EXTERNALS_ROOT}/lib/${CMAKE_BUILD_TYPE}")
set(BUILD_SDK OFF CACHE BOOL "Build the sdk")
set(BUILD_WEB ON CACHE BOOL "Build the web server")
include_directories(BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
link_directories(${SPARK_LIB})
@@ -53,12 +47,6 @@ else()
# make sparkd look for libspark.so in its directory
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH ".")
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install/${CMAKE_BUILD_TYPE}/sparkd")
add_compile_definitions(SPARK_ENABLE_CCAPI)
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_FTX)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE)
add_compile_definitions(CCAPI_ENABLE_LOG_WARN)
# flags
set(
@@ -79,9 +67,7 @@ else()
# subdirs
add_subdirectory(src/server/sparkd)
add_subdirectory(src/lib)
if (BUILD_WEB)
add_subdirectory(src/web)
endif()
add_subdirectory(src/web)
add_subdirectory(doc/user)
if(BUILD_SDK)
add_subdirectory(src/sdk)
@@ -105,9 +91,4 @@ else()
DEPENDS sparkd data_files_dir)
add_custom_target(server_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/server)
install(DIRECTORY "${CMAKE_BINARY_DIR}/server/plugins" DESTINATION bin)
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libACE-5.7.5.so" DESTINATION bin)
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0" DESTINATION bin)
install(FILES "${CMAKE_SOURCE_DIR}/externals/src/emumba/sparkd.lic" DESTINATION bin)
endif()
+25
View File
@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32630.192
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpreaderFrontEnd", "SpreaderFrontEnd\SpreaderFrontEnd.csproj", "{28EE9ABE-BBA6-4587-8BEB-3B0CD979ED22}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{28EE9ABE-BBA6-4587-8BEB-3B0CD979ED22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28EE9ABE-BBA6-4587-8BEB-3B0CD979ED22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28EE9ABE-BBA6-4587-8BEB-3B0CD979ED22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28EE9ABE-BBA6-4587-8BEB-3B0CD979ED22}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E2EF0DA-32BB-4A7A-9089-B132E1677AA7}
EndGlobalSection
EndGlobal
@@ -0,0 +1,36 @@
using System;
using System.Linq;
namespace SpreaderFrontEnd {
public class Book : IEquatable<Book> {
public Book(BookSide bids = null, BookSide asks = null) {
this.bids = bids ?? new BookSide();
this.asks = asks ?? new BookSide();
}
public BookSide bids { get; }
public BookSide asks { get; }
public Book Clone() {
return new Book(
new BookSide(bids.levels.ToList()),
new BookSide(asks.levels.ToList()));
}
public bool Equals(Book other) {
return other != null && other.bids.Equals(bids) && other.asks.Equals(asks);
}
public override bool Equals(object obj) {
return Equals(obj as Book);
}
public override int GetHashCode() {
return HashCodeHelper.combine(bids.GetHashCode(), asks.GetHashCode());
}
public override string ToString() {
return $"bid: {bids} | ask: {asks}";
}
}
}
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace SpreaderFrontEnd {
public class BookSide : IEquatable<BookSide> {
public BookSide() {
levels = new List<PriceLevel>();
}
public BookSide(IEnumerable<PriceLevel> levels) {
this.levels = levels?.ToList() ?? new List<PriceLevel>();
}
public IList<PriceLevel> levels { get; }
public BookSide Clone() {
return new BookSide(levels.ToList());
}
public bool Equals(BookSide other) {
return other != null && levels.SequenceEqual(other.levels);
}
public override bool Equals(object obj) {
return Equals(obj as BookSide);
}
public override int GetHashCode() {
return levels.Select(l => l.GetHashCode()).Skip(1).Aggregate(
levels[0].GetHashCode(), HashCodeHelper.combine);
}
public override string ToString() {
return string.Join("; ", levels);
}
}
}
@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace SpreaderFrontEnd {
public class LegCursor {
public LegCursor(int leg_size, IList<PriceLevel> levels) {
this.leg_size = leg_size;
this.levels = levels;
}
/// <summary>
/// The [signed] quantity of this leg in the SpreaderContract to which it belongs
/// </summary>
public int leg_size { get; }
/// <summary>
/// The [unsigned] quantity of this leg in the SpreaderContract to which it belongs
/// </summary>
public int leg_size_abs {
get {
return Math.Abs(leg_size);
}
}
/// <summary>
/// The price levels of the underlying BookSide
/// </summary>
public IList<PriceLevel> levels { get; }
/// <summary>
/// The index of the current level. When <see cref="consume_unit_qty(uint, out List{PriceLevel})"/>
/// is called, quantity consumption begins at this level. Once this level's quantity is fully
/// consumed, <see cref="cursor"/> is incremented, and <see cref="curr_level_consumed_qty"/>
/// is reset to 0.
/// </summary>
public int cursor { get; private set; }
/// <summary>
/// The quantity that has been consumed at the current level (i.e., the level at index
/// <see cref="cursor"/>)
/// </summary>
public uint curr_level_consumed_qty { get; private set; }
/// <summary>
/// Consumes the specified quantity of units at the best available price(s)
/// </summary>
/// <param name="unit_qty">
/// The unit quantity to consume
/// </param>
/// <returns>True if the entire quantity is consumed, otherwise false.</returns>
public bool consume_unit_qty(uint unit_qty, out List<PriceLevel> consumed_levels) {
consumed_levels = new List<PriceLevel>();
uint marg_qty = (uint)(unit_qty * leg_size_abs);
var consumed_qty = _consume_raw_qty(marg_qty, ref consumed_levels);
Debug.Assert(consumed_qty % leg_size_abs == 0);
uint consumed_units = (uint)(consumed_qty / leg_size_abs);
return consumed_units == unit_qty;
}
/// <summary>
/// Gets the number of units (raw_quantity / leg_size_abs) available at the best price
/// </summary>
public PriceLevel curr_synth_level() {
if (cursor >= levels.Count) {
return PriceLevel.empty;
}
var curr_level = levels[cursor];
Debug.Assert(curr_level.qty >= curr_level_consumed_qty);
var curr_level_rem_qty = curr_level.qty - curr_level_consumed_qty;
if (curr_level_rem_qty >= leg_size_abs) {
return new PriceLevel(
price: curr_level.price * leg_size_abs,
qty: (uint)(curr_level_rem_qty / leg_size_abs));
}
double unit_cost = curr_level.price * curr_level_rem_qty;
var unit_rem = leg_size_abs - curr_level_rem_qty;
for (int i = cursor + 1; i < levels.Count; i++) {
curr_level = levels[i];
if (curr_level.qty >= unit_rem) {
unit_cost += curr_level.price * unit_rem;
return new PriceLevel(price: unit_cost, qty: 1);
}
unit_cost += curr_level.price * curr_level.qty;
unit_rem -= curr_level.qty;
}
return PriceLevel.empty;
}
/// <summary>
/// Consumes as much of the specified [raw] quantity as possible
/// </summary>
/// <returns>
/// The quantity that was actually consumed
/// </returns>
uint _consume_raw_qty(uint raw_qty, ref List<PriceLevel> dest) {
if (levels == null || cursor >= levels.Count) {
return 0;
}
var curr_level = levels[cursor];
// Cursor should be incremented when curr_level_consumed_qty == levels[cursor].qty
// (i.e., curr_level.qty should never be less than curr_level_consumed_qty)
Debug.Assert(curr_level.qty > curr_level_consumed_qty);
var curr_level_qty_rem = curr_level.qty - curr_level_consumed_qty;
if (curr_level_qty_rem > raw_qty) {
curr_level_consumed_qty += raw_qty;
dest.Add(new PriceLevel(price: curr_level.price, qty: raw_qty));
return raw_qty;
}
// The input qty is greater than the qty that remains at this level. Consume the rest on
// the next level.
cursor++;
curr_level_consumed_qty = 0;
dest.Add(new PriceLevel(price: curr_level.price, qty: curr_level_qty_rem));
return curr_level_qty_rem + _consume_raw_qty(raw_qty - curr_level_qty_rem, ref dest);
}
}
}
@@ -0,0 +1,44 @@
using System;
namespace SpreaderFrontEnd {
public struct PriceLevel : IEquatable<PriceLevel> {
public PriceLevel(double price, uint qty) {
this.price = price;
this.qty = qty;
}
public static PriceLevel empty {
get {
return new PriceLevel(double.NaN, 0);
}
}
public double price { get; }
public uint qty { get; }
public PriceLevel subtract_qty(uint value) {
System.Diagnostics.Debug.Assert(value <= qty);
return new PriceLevel(price, qty - value);
}
public PriceLevel add_qty(uint value) {
return new PriceLevel(price, qty + value);
}
public override string ToString() {
return $"{price} ({qty})";
}
public bool Equals(PriceLevel other) {
return qty == other.qty && price.Equals(other.price);
}
public override bool Equals(object obj) {
return obj is PriceLevel other && Equals(other);
}
public override int GetHashCode() {
return HashCodeHelper.combine(price.GetHashCode(), qty.GetHashCode());
}
}
}
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
namespace SpreaderFrontEnd {
public static class SpreaderBookCalculator {
public static Book compute_spreader_book(
SpreaderContract contract, IEnumerable<Book> leg_books) {
if (contract == null) {
throw new ArgumentNullException(nameof(contract));
}
if (leg_books == null) {
throw new ArgumentNullException(nameof(leg_books));
}
var leg_book_list = leg_books as IList<Book> ?? leg_books.ToList();
var synth_book = new SyntheticBook(contract, leg_book_list);
return synth_book.to_book();
}
public static BookSide compute_spreader_book_side(
SpreaderContract contract, IList<Book> leg_books, bool is_bid) {
Debug.Assert(contract.spread_legs.Count == leg_books.Count);
var leg_cursors = leg_books.Select((b, i) => new LegCursor(
contract.spread_legs[i].qty,
contract.spread_legs[i].qty < 0 == is_bid ? b.asks.levels : b.bids.levels)).ToList();
var level_qty = leg_cursors.Select(lc => lc.curr_synth_level().qty).Min();
var result = new BookSide();
while (level_qty > 0) {
double level_price = 0;
for (int i = 0; i < leg_cursors.Count; i++) {
var lc = leg_cursors[i];
bool did_consume = lc.consume_unit_qty(level_qty, out var consumed_levels);
Debug.Assert(did_consume);
var leg_cost = consumed_levels.Select(l => l.price * l.qty).Sum() / level_qty;
if (lc.leg_size < 0) {
level_price -= leg_cost;
} else {
level_price += leg_cost;
}
}
result.levels.Add(new PriceLevel(price: level_price, qty: level_qty));
level_qty = leg_cursors.Select(lc => lc.curr_synth_level().qty).Min();
}
return result;
}
}
}
@@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace SpreaderFrontEnd {
class SyntheticBook {
public SyntheticBook(SpreaderContract contract, IList<Book> leg_books) {
bids = new SyntheticBookSide(contract, leg_books, true);
asks = new SyntheticBookSide(contract, leg_books, false);
}
public SyntheticBookSide bids { get; }
public SyntheticBookSide asks { get; }
public Book to_book() {
return new Book(bids: bids.to_book_side(), asks: asks.to_book_side());
}
}
}
@@ -0,0 +1,28 @@
using System.Collections;
using System.Collections.Generic;
namespace SpreaderFrontEnd {
class SyntheticBookSide : IEnumerable<PriceLevel> {
readonly SpreaderContract _contract;
readonly IList<Book> _leg_books;
readonly bool _is_bid;
public SyntheticBookSide(SpreaderContract contract, IList<Book> leg_books, bool is_bid) {
_contract = contract;
_leg_books = leg_books;
_is_bid = is_bid;
}
public BookSide to_book_side() {
return new BookSide(this);
}
public IEnumerator<PriceLevel> GetEnumerator() {
return new SyntheticBookSideEnumerator(_contract, _leg_books, _is_bid);
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
}
@@ -0,0 +1,59 @@
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Collections;
namespace SpreaderFrontEnd {
class SyntheticBookSideEnumerator : IEnumerator<PriceLevel> {
readonly List<LegCursor> _leg_cursors;
PriceLevel _current;
uint _level_qty;
public SyntheticBookSideEnumerator(
SpreaderContract contract, IList<Book> leg_books, bool is_bid) {
Debug.Assert(contract.spread_legs.Count == leg_books.Count);
_leg_cursors = new List<LegCursor>(leg_books.Count);
for (int i = 0; i < leg_books.Count; i++) {
_leg_cursors.Add(new LegCursor(
contract.spread_legs[i].qty,
contract.spread_legs[i].qty < 0 == is_bid ?
leg_books[i].asks.levels : leg_books[i].bids.levels));
}
}
public PriceLevel Current => _current;
object IEnumerator.Current => _current;
public void Dispose() { }
public bool MoveNext() {
_level_qty = _leg_cursors.Select(lc => lc.curr_synth_level().qty).Min();
if (_level_qty == 0) {
return false;
}
double level_price = 0;
for (int i = 0; i < _leg_cursors.Count; i++) {
var lc = _leg_cursors[i];
bool did_consume = lc.consume_unit_qty(_level_qty, out var consumed_levels);
Debug.Assert(did_consume);
var leg_cost = consumed_levels.Select(l => l.price * l.qty).Sum() / _level_qty;
if (lc.leg_size < 0) {
level_price -= leg_cost;
} else {
level_price += leg_cost;
}
}
_current = new PriceLevel(price: level_price, qty: _level_qty);
return true;
}
public void Reset() {
for (int i = 0; i < _leg_cursors.Count; i++) {
var lc = _leg_cursors[i];
_leg_cursors[i] = new LegCursor(lc.leg_size, lc.levels);
}
}
}
}
@@ -0,0 +1,8 @@
namespace SpreaderFrontEnd {
static class HashCodeHelper {
// Copied from https://referencesource.microsoft.com/#System.Numerics/System/Numerics/HashCodeHelper.cs
public static int combine(int h1, int h2) {
return (((h1 << 5) + h1) ^ h2);
}
}
}
+744
View File
@@ -0,0 +1,744 @@
using System.Windows.Forms;
namespace SpreaderFrontEnd
{
partial class LegControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this._combobox_security = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this._textbox_quote_qho_length = new System.Windows.Forms.TextBox();
this._textbox_quote_insidemarketdistance_towarddistance = new System.Windows.Forms.TextBox();
this._textbox_quote_conditional_ticks = new System.Windows.Forms.TextBox();
this._textbox_quote_throttle_outsideticks = new System.Windows.Forms.TextBox();
this._textbox_quote_throttle_insideticks = new System.Windows.Forms.TextBox();
this._textbox_quote_showqty_qty = new System.Windows.Forms.TextBox();
this.label11 = new System.Windows.Forms.Label();
this._checkbox_quote_insidemarketdistance = new System.Windows.Forms.CheckBox();
this.label10 = new System.Windows.Forms.Label();
this._checkbox_quote_conditional = new System.Windows.Forms.CheckBox();
this.label9 = new System.Windows.Forms.Label();
this.label8 = new System.Windows.Forms.Label();
this._checkbox_quote_throttle = new System.Windows.Forms.CheckBox();
this.label7 = new System.Windows.Forms.Label();
this._checkbox_quote_showqty = new System.Windows.Forms.CheckBox();
this.label6 = new System.Windows.Forms.Label();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this._textbox_prehedge_payless_paylessticks = new System.Windows.Forms.TextBox();
this._textbox_prehedge_payup_payupticks = new System.Windows.Forms.TextBox();
this._textbox_prehedge_payup_threshold = new System.Windows.Forms.TextBox();
this._textbox_prehedge_payless_threshold = new System.Windows.Forms.TextBox();
this.label13 = new System.Windows.Forms.Label();
this.label14 = new System.Windows.Forms.Label();
this.label15 = new System.Windows.Forms.Label();
this._checkbox_prehedge_payup = new System.Windows.Forms.CheckBox();
this.label16 = new System.Windows.Forms.Label();
this._checkbox_prehedge_payless = new System.Windows.Forms.CheckBox();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this._textbox_posthedge_sizebasedcross_crossticks = new System.Windows.Forms.TextBox();
this._textbox_posthedge_sizebasedcross_threshold = new System.Windows.Forms.TextBox();
this._textbox_posthedge_timesbasedcross_crossticks = new System.Windows.Forms.TextBox();
this._textbox_posthedge_timesbasedcross_timems = new System.Windows.Forms.TextBox();
this._textbox_posthedge_ticksawaycross_crossticks = new System.Windows.Forms.TextBox();
this._textbox_posthedge_ticksawaycross_threshold = new System.Windows.Forms.TextBox();
this.label20 = new System.Windows.Forms.Label();
this.label21 = new System.Windows.Forms.Label();
this._checkbox_posthedge_sizebasedcross = new System.Windows.Forms.CheckBox();
this.label12 = new System.Windows.Forms.Label();
this.label17 = new System.Windows.Forms.Label();
this.label18 = new System.Windows.Forms.Label();
this._checkbox_posthedge_timebasedcross = new System.Windows.Forms.CheckBox();
this.label19 = new System.Windows.Forms.Label();
this._checkbox_posthedge_ticksawaycross = new System.Windows.Forms.CheckBox();
this._textbox_leg_qty = new System.Windows.Forms.TextBox();
this._checkbox_leg_enablequoting = new System.Windows.Forms.CheckBox();
this._textbox_leg_leanqtyfactor = new System.Windows.Forms.TextBox();
this._combobox_mdtype = new System.Windows.Forms.ComboBox();
this._textbox_leg_price_mult = new System.Windows.Forms.TextBox();
this.label4 = new System.Windows.Forms.Label();
this._label_leanqty_factor = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.SuspendLayout();
//
// _combobox_security
//
this._combobox_security.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this._combobox_security.FormattingEnabled = true;
this._combobox_security.Location = new System.Drawing.Point(157, 15);
this._combobox_security.Name = "_combobox_security";
this._combobox_security.Size = new System.Drawing.Size(100, 23);
this._combobox_security.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(16, 23);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(49, 15);
this.label1.TabIndex = 1;
this.label1.Text = "Security";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(16, 58);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(53, 15);
this.label2.TabIndex = 2;
this.label2.Text = "Quantity";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(16, 128);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(89, 15);
this.label3.TabIndex = 3;
this.label3.Text = "Enable Quoting";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(16, 198);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(98, 15);
this.label5.TabIndex = 5;
this.label5.Text = "Market Data Type";
//
// groupBox1
//
this.groupBox1.Controls.Add(this._textbox_quote_qho_length);
this.groupBox1.Controls.Add(this._textbox_quote_insidemarketdistance_towarddistance);
this.groupBox1.Controls.Add(this._textbox_quote_conditional_ticks);
this.groupBox1.Controls.Add(this._textbox_quote_throttle_outsideticks);
this.groupBox1.Controls.Add(this._textbox_quote_throttle_insideticks);
this.groupBox1.Controls.Add(this._textbox_quote_showqty_qty);
this.groupBox1.Controls.Add(this.label11);
this.groupBox1.Controls.Add(this._checkbox_quote_insidemarketdistance);
this.groupBox1.Controls.Add(this.label10);
this.groupBox1.Controls.Add(this._checkbox_quote_conditional);
this.groupBox1.Controls.Add(this.label9);
this.groupBox1.Controls.Add(this.label8);
this.groupBox1.Controls.Add(this._checkbox_quote_throttle);
this.groupBox1.Controls.Add(this.label7);
this.groupBox1.Controls.Add(this._checkbox_quote_showqty);
this.groupBox1.Controls.Add(this.label6);
this.groupBox1.ForeColor = System.Drawing.Color.Black;
this.groupBox1.Location = new System.Drawing.Point(12, 238);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(265, 369);
this.groupBox1.TabIndex = 6;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Quote";
//
// _textbox_quote_qho_length
//
this._textbox_quote_qho_length.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_qho_length.Location = new System.Drawing.Point(145, 28);
this._textbox_quote_qho_length.Name = "_textbox_quote_qho_length";
this._textbox_quote_qho_length.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_qho_length.TabIndex = 6;
//
// _textbox_quote_insidemarketdistance_towarddistance
//
this._textbox_quote_insidemarketdistance_towarddistance.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_insidemarketdistance_towarddistance.Location = new System.Drawing.Point(145, 314);
this._textbox_quote_insidemarketdistance_towarddistance.Name = "_textbox_quote_insidemarketdistance_towarddistance";
this._textbox_quote_insidemarketdistance_towarddistance.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_insidemarketdistance_towarddistance.TabIndex = 15;
//
// _textbox_quote_conditional_ticks
//
this._textbox_quote_conditional_ticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_conditional_ticks.Location = new System.Drawing.Point(145, 250);
this._textbox_quote_conditional_ticks.Name = "_textbox_quote_conditional_ticks";
this._textbox_quote_conditional_ticks.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_conditional_ticks.TabIndex = 13;
//
// _textbox_quote_throttle_outsideticks
//
this._textbox_quote_throttle_outsideticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_throttle_outsideticks.Location = new System.Drawing.Point(145, 186);
this._textbox_quote_throttle_outsideticks.Name = "_textbox_quote_throttle_outsideticks";
this._textbox_quote_throttle_outsideticks.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_throttle_outsideticks.TabIndex = 11;
//
// _textbox_quote_throttle_insideticks
//
this._textbox_quote_throttle_insideticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_throttle_insideticks.Location = new System.Drawing.Point(145, 156);
this._textbox_quote_throttle_insideticks.Name = "_textbox_quote_throttle_insideticks";
this._textbox_quote_throttle_insideticks.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_throttle_insideticks.TabIndex = 10;
//
// _textbox_quote_showqty_qty
//
this._textbox_quote_showqty_qty.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_quote_showqty_qty.Location = new System.Drawing.Point(145, 92);
this._textbox_quote_showqty_qty.Name = "_textbox_quote_showqty_qty";
this._textbox_quote_showqty_qty.Size = new System.Drawing.Size(100, 23);
this._textbox_quote_showqty_qty.TabIndex = 8;
//
// label11
//
this.label11.AutoSize = true;
this.label11.Location = new System.Drawing.Point(45, 322);
this.label11.Name = "label11";
this.label11.Size = new System.Drawing.Size(93, 15);
this.label11.TabIndex = 16;
this.label11.Text = "Toward Distance";
//
// _checkbox_quote_insidemarketdistance
//
this._checkbox_quote_insidemarketdistance.AutoSize = true;
this._checkbox_quote_insidemarketdistance.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_quote_insidemarketdistance.Location = new System.Drawing.Point(15, 288);
this._checkbox_quote_insidemarketdistance.Name = "_checkbox_quote_insidemarketdistance";
this._checkbox_quote_insidemarketdistance.Size = new System.Drawing.Size(131, 19);
this._checkbox_quote_insidemarketdistance.TabIndex = 14;
this._checkbox_quote_insidemarketdistance.Text = "Inside Market Dist.";
this._checkbox_quote_insidemarketdistance.UseVisualStyleBackColor = true;
this._checkbox_quote_insidemarketdistance.CheckedChanged += new System.EventHandler(this._checkbox_quote_insidemarketdistance_CheckedChanged);
//
// label10
//
this.label10.AutoSize = true;
this.label10.Location = new System.Drawing.Point(47, 258);
this.label10.Name = "label10";
this.label10.Size = new System.Drawing.Size(33, 15);
this.label10.TabIndex = 14;
this.label10.Text = "Ticks";
//
// _checkbox_quote_conditional
//
this._checkbox_quote_conditional.AutoSize = true;
this._checkbox_quote_conditional.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_quote_conditional.Location = new System.Drawing.Point(15, 224);
this._checkbox_quote_conditional.Name = "_checkbox_quote_conditional";
this._checkbox_quote_conditional.Size = new System.Drawing.Size(88, 19);
this._checkbox_quote_conditional.TabIndex = 12;
this._checkbox_quote_conditional.Text = "Conditional";
this._checkbox_quote_conditional.UseVisualStyleBackColor = true;
this._checkbox_quote_conditional.CheckedChanged += new System.EventHandler(this._checkbox_quote_conditional_CheckedChanged);
//
// label9
//
this.label9.AutoSize = true;
this.label9.Location = new System.Drawing.Point(45, 194);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(77, 15);
this.label9.TabIndex = 12;
this.label9.Text = "Outside Ticks";
//
// label8
//
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(45, 164);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(67, 15);
this.label8.TabIndex = 11;
this.label8.Text = "Inside Ticks";
//
// _checkbox_quote_throttle
//
this._checkbox_quote_throttle.AutoSize = true;
this._checkbox_quote_throttle.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_quote_throttle.Location = new System.Drawing.Point(15, 130);
this._checkbox_quote_throttle.Name = "_checkbox_quote_throttle";
this._checkbox_quote_throttle.Size = new System.Drawing.Size(72, 19);
this._checkbox_quote_throttle.TabIndex = 9;
this._checkbox_quote_throttle.Text = "Throttle";
this._checkbox_quote_throttle.UseVisualStyleBackColor = true;
this._checkbox_quote_throttle.CheckedChanged += new System.EventHandler(this._checkbox_quote_throttle_CheckedChanged);
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(45, 100);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(53, 15);
this.label7.TabIndex = 9;
this.label7.Text = "Quantity";
//
// _checkbox_quote_showqty
//
this._checkbox_quote_showqty.AutoSize = true;
this._checkbox_quote_showqty.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_quote_showqty.Location = new System.Drawing.Point(15, 66);
this._checkbox_quote_showqty.Name = "_checkbox_quote_showqty";
this._checkbox_quote_showqty.Size = new System.Drawing.Size(108, 19);
this._checkbox_quote_showqty.TabIndex = 7;
this._checkbox_quote_showqty.Text = "Show Quantity";
this._checkbox_quote_showqty.UseVisualStyleBackColor = true;
this._checkbox_quote_showqty.CheckedChanged += new System.EventHandler(this._checkbox_quote_showqty_CheckedChanged);
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(15, 36);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(121, 15);
this.label6.TabIndex = 6;
this.label6.Text = "Queue Holder Length";
//
// groupBox2
//
this.groupBox2.Controls.Add(this._textbox_prehedge_payless_paylessticks);
this.groupBox2.Controls.Add(this._textbox_prehedge_payup_payupticks);
this.groupBox2.Controls.Add(this._textbox_prehedge_payup_threshold);
this.groupBox2.Controls.Add(this._textbox_prehedge_payless_threshold);
this.groupBox2.Controls.Add(this.label13);
this.groupBox2.Controls.Add(this.label14);
this.groupBox2.Controls.Add(this.label15);
this.groupBox2.Controls.Add(this._checkbox_prehedge_payup);
this.groupBox2.Controls.Add(this.label16);
this.groupBox2.Controls.Add(this._checkbox_prehedge_payless);
this.groupBox2.Location = new System.Drawing.Point(13, 626);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(264, 234);
this.groupBox2.TabIndex = 7;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Pre-Hedge";
//
// _textbox_prehedge_payless_paylessticks
//
this._textbox_prehedge_payless_paylessticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_prehedge_payless_paylessticks.Location = new System.Drawing.Point(144, 90);
this._textbox_prehedge_payless_paylessticks.Name = "_textbox_prehedge_payless_paylessticks";
this._textbox_prehedge_payless_paylessticks.Size = new System.Drawing.Size(100, 23);
this._textbox_prehedge_payless_paylessticks.TabIndex = 18;
//
// _textbox_prehedge_payup_payupticks
//
this._textbox_prehedge_payup_payupticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_prehedge_payup_payupticks.Location = new System.Drawing.Point(144, 187);
this._textbox_prehedge_payup_payupticks.Name = "_textbox_prehedge_payup_payupticks";
this._textbox_prehedge_payup_payupticks.Size = new System.Drawing.Size(100, 23);
this._textbox_prehedge_payup_payupticks.TabIndex = 21;
//
// _textbox_prehedge_payup_threshold
//
this._textbox_prehedge_payup_threshold.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_prehedge_payup_threshold.Location = new System.Drawing.Point(144, 156);
this._textbox_prehedge_payup_threshold.Name = "_textbox_prehedge_payup_threshold";
this._textbox_prehedge_payup_threshold.Size = new System.Drawing.Size(100, 23);
this._textbox_prehedge_payup_threshold.TabIndex = 20;
//
// _textbox_prehedge_payless_threshold
//
this._textbox_prehedge_payless_threshold.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_prehedge_payless_threshold.Location = new System.Drawing.Point(144, 59);
this._textbox_prehedge_payless_threshold.Name = "_textbox_prehedge_payless_threshold";
this._textbox_prehedge_payless_threshold.Size = new System.Drawing.Size(100, 23);
this._textbox_prehedge_payless_threshold.TabIndex = 17;
//
// label13
//
this.label13.AutoSize = true;
this.label13.Location = new System.Drawing.Point(44, 98);
this.label13.Name = "label13";
this.label13.Size = new System.Drawing.Size(74, 15);
this.label13.TabIndex = 14;
this.label13.Text = "Payless Ticks";
//
// label14
//
this.label14.AutoSize = true;
this.label14.Location = new System.Drawing.Point(44, 195);
this.label14.Name = "label14";
this.label14.Size = new System.Drawing.Size(69, 15);
this.label14.TabIndex = 12;
this.label14.Text = "Payup Ticks";
//
// label15
//
this.label15.AutoSize = true;
this.label15.Location = new System.Drawing.Point(44, 164);
this.label15.Name = "label15";
this.label15.Size = new System.Drawing.Size(59, 15);
this.label15.TabIndex = 11;
this.label15.Text = "Threshold";
//
// _checkbox_prehedge_payup
//
this._checkbox_prehedge_payup.AutoSize = true;
this._checkbox_prehedge_payup.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_prehedge_payup.Location = new System.Drawing.Point(15, 129);
this._checkbox_prehedge_payup.Name = "_checkbox_prehedge_payup";
this._checkbox_prehedge_payup.Size = new System.Drawing.Size(64, 19);
this._checkbox_prehedge_payup.TabIndex = 19;
this._checkbox_prehedge_payup.Text = "Pay Up";
this._checkbox_prehedge_payup.UseVisualStyleBackColor = true;
this._checkbox_prehedge_payup.CheckedChanged += new System.EventHandler(this._checkbox_prehedge_payup_CheckedChanged);
//
// label16
//
this.label16.AutoSize = true;
this.label16.Location = new System.Drawing.Point(44, 67);
this.label16.Name = "label16";
this.label16.Size = new System.Drawing.Size(59, 15);
this.label16.TabIndex = 9;
this.label16.Text = "Threshold";
//
// _checkbox_prehedge_payless
//
this._checkbox_prehedge_payless.AutoSize = true;
this._checkbox_prehedge_payless.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_prehedge_payless.Location = new System.Drawing.Point(15, 32);
this._checkbox_prehedge_payless.Name = "_checkbox_prehedge_payless";
this._checkbox_prehedge_payless.Size = new System.Drawing.Size(71, 19);
this._checkbox_prehedge_payless.TabIndex = 16;
this._checkbox_prehedge_payless.Text = "Pay Less";
this._checkbox_prehedge_payless.UseVisualStyleBackColor = true;
this._checkbox_prehedge_payless.CheckedChanged += new System.EventHandler(this._checkbox_prehedge_payless_CheckedChanged);
//
// groupBox3
//
this.groupBox3.Controls.Add(this._textbox_posthedge_sizebasedcross_crossticks);
this.groupBox3.Controls.Add(this._textbox_posthedge_sizebasedcross_threshold);
this.groupBox3.Controls.Add(this._textbox_posthedge_timesbasedcross_crossticks);
this.groupBox3.Controls.Add(this._textbox_posthedge_timesbasedcross_timems);
this.groupBox3.Controls.Add(this._textbox_posthedge_ticksawaycross_crossticks);
this.groupBox3.Controls.Add(this._textbox_posthedge_ticksawaycross_threshold);
this.groupBox3.Controls.Add(this.label20);
this.groupBox3.Controls.Add(this.label21);
this.groupBox3.Controls.Add(this._checkbox_posthedge_sizebasedcross);
this.groupBox3.Controls.Add(this.label12);
this.groupBox3.Controls.Add(this.label17);
this.groupBox3.Controls.Add(this.label18);
this.groupBox3.Controls.Add(this._checkbox_posthedge_timebasedcross);
this.groupBox3.Controls.Add(this.label19);
this.groupBox3.Controls.Add(this._checkbox_posthedge_ticksawaycross);
this.groupBox3.Location = new System.Drawing.Point(13, 882);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(264, 319);
this.groupBox3.TabIndex = 8;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Post-Hedge";
//
// _textbox_posthedge_sizebasedcross_crossticks
//
this._textbox_posthedge_sizebasedcross_crossticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_sizebasedcross_crossticks.Location = new System.Drawing.Point(144, 276);
this._textbox_posthedge_sizebasedcross_crossticks.Name = "_textbox_posthedge_sizebasedcross_crossticks";
this._textbox_posthedge_sizebasedcross_crossticks.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_sizebasedcross_crossticks.TabIndex = 30;
//
// _textbox_posthedge_sizebasedcross_threshold
//
this._textbox_posthedge_sizebasedcross_threshold.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_sizebasedcross_threshold.Location = new System.Drawing.Point(144, 246);
this._textbox_posthedge_sizebasedcross_threshold.Name = "_textbox_posthedge_sizebasedcross_threshold";
this._textbox_posthedge_sizebasedcross_threshold.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_sizebasedcross_threshold.TabIndex = 29;
//
// _textbox_posthedge_timesbasedcross_crossticks
//
this._textbox_posthedge_timesbasedcross_crossticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_timesbasedcross_crossticks.Location = new System.Drawing.Point(144, 182);
this._textbox_posthedge_timesbasedcross_crossticks.Name = "_textbox_posthedge_timesbasedcross_crossticks";
this._textbox_posthedge_timesbasedcross_crossticks.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_timesbasedcross_crossticks.TabIndex = 27;
//
// _textbox_posthedge_timesbasedcross_timems
//
this._textbox_posthedge_timesbasedcross_timems.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_timesbasedcross_timems.Location = new System.Drawing.Point(144, 152);
this._textbox_posthedge_timesbasedcross_timems.Name = "_textbox_posthedge_timesbasedcross_timems";
this._textbox_posthedge_timesbasedcross_timems.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_timesbasedcross_timems.TabIndex = 26;
//
// _textbox_posthedge_ticksawaycross_crossticks
//
this._textbox_posthedge_ticksawaycross_crossticks.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_ticksawaycross_crossticks.Location = new System.Drawing.Point(144, 88);
this._textbox_posthedge_ticksawaycross_crossticks.Name = "_textbox_posthedge_ticksawaycross_crossticks";
this._textbox_posthedge_ticksawaycross_crossticks.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_ticksawaycross_crossticks.TabIndex = 24;
//
// _textbox_posthedge_ticksawaycross_threshold
//
this._textbox_posthedge_ticksawaycross_threshold.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_posthedge_ticksawaycross_threshold.Location = new System.Drawing.Point(144, 58);
this._textbox_posthedge_ticksawaycross_threshold.Name = "_textbox_posthedge_ticksawaycross_threshold";
this._textbox_posthedge_ticksawaycross_threshold.Size = new System.Drawing.Size(100, 23);
this._textbox_posthedge_ticksawaycross_threshold.TabIndex = 23;
//
// label20
//
this.label20.AutoSize = true;
this.label20.Location = new System.Drawing.Point(44, 284);
this.label20.Name = "label20";
this.label20.Size = new System.Drawing.Size(65, 15);
this.label20.TabIndex = 17;
this.label20.Text = "Cross Ticks";
//
// label21
//
this.label21.AutoSize = true;
this.label21.Location = new System.Drawing.Point(44, 254);
this.label21.Name = "label21";
this.label21.Size = new System.Drawing.Size(59, 15);
this.label21.TabIndex = 16;
this.label21.Text = "Threshold";
//
// _checkbox_posthedge_sizebasedcross
//
this._checkbox_posthedge_sizebasedcross.AutoSize = true;
this._checkbox_posthedge_sizebasedcross.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_posthedge_sizebasedcross.Location = new System.Drawing.Point(15, 220);
this._checkbox_posthedge_sizebasedcross.Name = "_checkbox_posthedge_sizebasedcross";
this._checkbox_posthedge_sizebasedcross.Size = new System.Drawing.Size(117, 19);
this._checkbox_posthedge_sizebasedcross.TabIndex = 28;
this._checkbox_posthedge_sizebasedcross.Text = "Size Based Cross";
this._checkbox_posthedge_sizebasedcross.UseVisualStyleBackColor = true;
this._checkbox_posthedge_sizebasedcross.CheckedChanged += new System.EventHandler(this._checkbox_posthedge_sizebasedcross_CheckedChanged);
//
// label12
//
this.label12.AutoSize = true;
this.label12.Location = new System.Drawing.Point(44, 96);
this.label12.Name = "label12";
this.label12.Size = new System.Drawing.Size(65, 15);
this.label12.TabIndex = 14;
this.label12.Text = "Cross Ticks";
//
// label17
//
this.label17.AutoSize = true;
this.label17.Location = new System.Drawing.Point(44, 190);
this.label17.Name = "label17";
this.label17.Size = new System.Drawing.Size(65, 15);
this.label17.TabIndex = 12;
this.label17.Text = "Cross Ticks";
//
// label18
//
this.label18.AutoSize = true;
this.label18.Location = new System.Drawing.Point(44, 160);
this.label18.Name = "label18";
this.label18.Size = new System.Drawing.Size(57, 15);
this.label18.TabIndex = 11;
this.label18.Text = "Time(ms)";
//
// _checkbox_posthedge_timebasedcross
//
this._checkbox_posthedge_timebasedcross.AutoSize = true;
this._checkbox_posthedge_timebasedcross.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_posthedge_timebasedcross.Location = new System.Drawing.Point(15, 126);
this._checkbox_posthedge_timebasedcross.Name = "_checkbox_posthedge_timebasedcross";
this._checkbox_posthedge_timebasedcross.Size = new System.Drawing.Size(122, 19);
this._checkbox_posthedge_timebasedcross.TabIndex = 25;
this._checkbox_posthedge_timebasedcross.Text = "Time Based Cross";
this._checkbox_posthedge_timebasedcross.UseVisualStyleBackColor = true;
this._checkbox_posthedge_timebasedcross.CheckedChanged += new System.EventHandler(this._checkbox_posthedge_timebasedcross_CheckedChanged);
//
// label19
//
this.label19.AutoSize = true;
this.label19.Location = new System.Drawing.Point(44, 66);
this.label19.Name = "label19";
this.label19.Size = new System.Drawing.Size(59, 15);
this.label19.TabIndex = 9;
this.label19.Text = "Threshold";
//
// _checkbox_posthedge_ticksawaycross
//
this._checkbox_posthedge_ticksawaycross.AutoSize = true;
this._checkbox_posthedge_ticksawaycross.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this._checkbox_posthedge_ticksawaycross.Location = new System.Drawing.Point(15, 32);
this._checkbox_posthedge_ticksawaycross.Name = "_checkbox_posthedge_ticksawaycross";
this._checkbox_posthedge_ticksawaycross.Size = new System.Drawing.Size(119, 19);
this._checkbox_posthedge_ticksawaycross.TabIndex = 22;
this._checkbox_posthedge_ticksawaycross.Text = "Ticks Away Cross";
this._checkbox_posthedge_ticksawaycross.UseVisualStyleBackColor = true;
this._checkbox_posthedge_ticksawaycross.CheckedChanged += new System.EventHandler(this._checkbox_posthedge_ticksawaycross_CheckedChanged);
//
// _textbox_leg_qty
//
this._textbox_leg_qty.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_leg_qty.Location = new System.Drawing.Point(157, 50);
this._textbox_leg_qty.Name = "_textbox_leg_qty";
this._textbox_leg_qty.Size = new System.Drawing.Size(100, 23);
this._textbox_leg_qty.TabIndex = 1;
this._textbox_leg_qty.Tag = "Double";
//
// _checkbox_leg_enablequoting
//
this._checkbox_leg_enablequoting.AutoSize = true;
this._checkbox_leg_enablequoting.Location = new System.Drawing.Point(157, 129);
this._checkbox_leg_enablequoting.Name = "_checkbox_leg_enablequoting";
this._checkbox_leg_enablequoting.Size = new System.Drawing.Size(15, 14);
this._checkbox_leg_enablequoting.TabIndex = 3;
this._checkbox_leg_enablequoting.UseVisualStyleBackColor = true;
//
// _textbox_leg_leanqtyfactor
//
this._textbox_leg_leanqtyfactor.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_leg_leanqtyfactor.Location = new System.Drawing.Point(157, 155);
this._textbox_leg_leanqtyfactor.Name = "_textbox_leg_leanqtyfactor";
this._textbox_leg_leanqtyfactor.Size = new System.Drawing.Size(100, 23);
this._textbox_leg_leanqtyfactor.TabIndex = 4;
//
// _combobox_mdtype
//
this._combobox_mdtype.AutoCompleteCustomSource.AddRange(new string[] {
"Merged",
"Direct"});
this._combobox_mdtype.FormattingEnabled = true;
this._combobox_mdtype.Location = new System.Drawing.Point(157, 190);
this._combobox_mdtype.Name = "_combobox_mdtype";
this._combobox_mdtype.Size = new System.Drawing.Size(100, 23);
this._combobox_mdtype.TabIndex = 5;
//
// _textbox_leg_price_mult
//
this._textbox_leg_price_mult.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this._textbox_leg_price_mult.Location = new System.Drawing.Point(157, 85);
this._textbox_leg_price_mult.Name = "_textbox_leg_price_mult";
this._textbox_leg_price_mult.Size = new System.Drawing.Size(100, 23);
this._textbox_leg_price_mult.TabIndex = 2;
this._textbox_leg_price_mult.Tag = "Double";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(16, 93);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(87, 15);
this.label4.TabIndex = 10;
this.label4.Text = "Price Multiplier";
//
// _label_leanqty_factor
//
this._label_leanqty_factor.AutoSize = true;
this._label_leanqty_factor.Location = new System.Drawing.Point(16, 163);
this._label_leanqty_factor.Name = "_label_leanqty_factor";
this._label_leanqty_factor.Size = new System.Drawing.Size(90, 15);
this._label_leanqty_factor.TabIndex = 4;
this._label_leanqty_factor.Text = "Lean Qty Factor";
//
// LegControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.Controls.Add(this._textbox_leg_price_mult);
this.Controls.Add(this.label4);
this.Controls.Add(this._combobox_mdtype);
this.Controls.Add(this._textbox_leg_leanqtyfactor);
this.Controls.Add(this._checkbox_leg_enablequoting);
this.Controls.Add(this._textbox_leg_qty);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.label5);
this.Controls.Add(this._label_leanqty_factor);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this._combobox_security);
this.Name = "LegControl";
this.Size = new System.Drawing.Size(291, 1220);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.groupBox3.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private ComboBox _combobox_security;
private Label label1;
private Label label2;
private Label label3;
private Label label5;
private GroupBox groupBox1;
private Label label6;
private Label label11;
private CheckBox _checkbox_quote_insidemarketdistance;
private Label label10;
private CheckBox _checkbox_quote_conditional;
private Label label9;
private Label label8;
private CheckBox _checkbox_quote_throttle;
private Label label7;
private CheckBox _checkbox_quote_showqty;
private GroupBox groupBox2;
private Label label13;
private Label label14;
private Label label15;
private CheckBox _checkbox_prehedge_payup;
private Label label16;
private CheckBox _checkbox_prehedge_payless;
private GroupBox groupBox3;
private Label label20;
private Label label21;
private CheckBox _checkbox_posthedge_sizebasedcross;
private Label label12;
private Label label17;
private Label label18;
private CheckBox _checkbox_posthedge_timebasedcross;
private Label label19;
private CheckBox _checkbox_posthedge_ticksawaycross;
private TextBox _textbox_leg_qty;
private CheckBox _checkbox_leg_enablequoting;
private TextBox _textbox_leg_leanqtyfactor;
private ComboBox _combobox_mdtype;
private TextBox _textbox_quote_insidemarketdistance_towarddistance;
private TextBox _textbox_quote_conditional_ticks;
private TextBox _textbox_quote_throttle_outsideticks;
private TextBox _textbox_quote_throttle_insideticks;
private TextBox _textbox_quote_showqty_qty;
private TextBox _textbox_prehedge_payless_paylessticks;
private TextBox _textbox_prehedge_payup_payupticks;
private TextBox _textbox_prehedge_payup_threshold;
private TextBox _textbox_prehedge_payless_threshold;
private TextBox _textbox_posthedge_sizebasedcross_crossticks;
private TextBox _textbox_posthedge_sizebasedcross_threshold;
private TextBox _textbox_posthedge_timesbasedcross_crossticks;
private TextBox _textbox_posthedge_timesbasedcross_timems;
private TextBox _textbox_posthedge_ticksawaycross_crossticks;
private TextBox _textbox_posthedge_ticksawaycross_threshold;
private TextBox _textbox_quote_qho_length;
private TextBox _textbox_leg_price_mult;
private Label label4;
private Label _label_leanqty_factor;
}
}
@@ -0,0 +1,305 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Reflection;
namespace SpreaderFrontEnd {
// UI control that represents a spreader leg. This is hidden within the MainSpreaderForm
public partial class LegControl : UserControl {
private SpreaderLegContract _leg_contract = new SpreaderLegContract();
private IEnumerable<string> _securities = new List<string>();
public LegControl() {
InitializeComponent();
}
public void initialize(IEnumerable<string> securities, SpreaderLegContract? leg_contract) {
_securities = securities;
_leg_contract = leg_contract ?? new SpreaderLegContract();
_populate_ui();
}
#region Data -> UI
private void _populate_ui() {
_populate_basic();
_populate_quote();
_populate_prehedge();
_populate_posthedge();
_initialize_enablement();
_assign_events();
}
void _assign_events() {
foreach (System.Reflection.FieldInfo fi in GetType().GetFields(BindingFlags.NonPublic
| BindingFlags.Public
| BindingFlags.Instance)) {
if (fi.FieldType == typeof(TextBox)) {
object? val = fi.GetValue(this);
if (val != null) {
TextBox? textbox = val as TextBox;
if (textbox != null) {
textbox.TextChanged += Textbox_TextChanged;
textbox.EnabledChanged += Textbox_EnabledChanged;
}
}
}
}
}
private void Textbox_EnabledChanged(object? sender, EventArgs e) {
}
private void Textbox_TextChanged(object? sender, EventArgs e) {
if (sender != null && sender is TextBox) {
TextBox? tb = sender as TextBox;
if (tb == null)
return;
if ("Double".Equals(tb.Tag)) {
double res;
bool parsed = Double.TryParse(tb.Text, out res);
tb.ForeColor = parsed ? Color.Black : Color.Red;
} else {
UInt32 res;
bool parsed = UInt32.TryParse(tb.Text, out res);
tb.ForeColor = parsed ? Color.Black : Color.Red;
}
}
}
void _populate_basic() {
// security
_combobox_security.Items.Clear();
List<string> securities_plus_empty = new List<string>(_securities);
securities_plus_empty.Add(String.Empty);
_combobox_security.Items.AddRange(securities_plus_empty.ToArray());
_combobox_security.Text = _leg_contract.security;
// qty etc
_textbox_leg_qty.Text = _leg_contract.qty.ToString();
_textbox_leg_price_mult.Text = _leg_contract.price_mult.ToString();
_checkbox_leg_enablequoting.Checked = _leg_contract.enable_quoting;
_textbox_leg_leanqtyfactor.Text = _leg_contract.lean_qty_factor.ToString();
_combobox_mdtype.Text = _leg_contract.md_type.ToString();
}
void _populate_quote() {
Debug.Assert(_leg_contract.quote_params != null);
var qp = _leg_contract.quote_params;
_textbox_quote_qho_length.Text = qp.qho_length.ToString();
// show qty
_checkbox_quote_showqty.Checked = qp.show_qty != null;
if (qp.show_qty != null) {
_checkbox_quote_showqty.Checked = true;
_textbox_quote_showqty_qty.Text = qp.show_qty.show_qty.ToString();
}
// throttle
_checkbox_quote_throttle.Checked = qp.throttle != null;
if (qp.throttle != null) {
_textbox_quote_throttle_insideticks.Text = qp.throttle.inside_ticks.ToString();
_textbox_quote_throttle_outsideticks.Text = qp.throttle.outside_ticks.ToString();
}
// conditional
_checkbox_quote_conditional.Checked = qp.conditional != null;
if (qp.conditional != null) {
_textbox_quote_conditional_ticks.Text = qp.conditional.ticks.ToString();
}
// inside market dist.
_checkbox_quote_insidemarketdistance.Checked = qp.inside_market_distance != null;
if (qp.inside_market_distance != null) {
_textbox_quote_insidemarketdistance_towarddistance.Text = qp.inside_market_distance.ToString();
}
}
void _populate_prehedge() {
var ph = _leg_contract.pre_hedge_params;
// payless
_checkbox_prehedge_payless.Checked = ph.payless != null;
if (ph.payless != null) {
_textbox_prehedge_payless_threshold.Text = ph.payless.threshold.ToString();
_textbox_prehedge_payless_paylessticks.Text = ph.payless.payless_ticks.ToString();
}
// payup
_checkbox_prehedge_payup.Checked = ph.payup != null;
if (ph.payup != null) {
_textbox_prehedge_payup_threshold.Text = ph.payup.threshold.ToString();
_textbox_prehedge_payup_payupticks.Text = ph.payup.payup_ticks.ToString();
}
}
void _populate_posthedge() {
var ph = _leg_contract.post_hedge_params;
_checkbox_posthedge_ticksawaycross.Checked = ph.ticks_away_cross != null;
// ticks away cross
if (ph.ticks_away_cross != null) {
_textbox_posthedge_ticksawaycross_threshold.Text = ph.ticks_away_cross.threshold.ToString();
_textbox_posthedge_ticksawaycross_crossticks.Text = ph.ticks_away_cross.cross_ticks.ToString();
}
//time based cross
_checkbox_posthedge_timebasedcross.Checked = ph.time_based_cross != null;
if (ph.time_based_cross != null) {
_textbox_posthedge_timesbasedcross_timems.Text = ph.time_based_cross.time_ms.ToString();
_textbox_posthedge_timesbasedcross_crossticks.Text = ph.time_based_cross.cross_ticks.ToString();
}
// size based cross
_checkbox_posthedge_sizebasedcross.Checked = ph.size_based_cross != null;
if (ph.size_based_cross != null) {
_textbox_posthedge_sizebasedcross_threshold.Text = ph.size_based_cross.threshold.ToString();
_textbox_posthedge_sizebasedcross_crossticks.Text = ph.size_based_cross.ToString();
}
}
// forces checkbox events so that the text boxes connected to it are enabled/disabled
private void _initialize_enablement() {
_checkbox_quote_showqty_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_quote_throttle_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_quote_conditional_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_quote_insidemarketdistance_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_prehedge_payless_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_prehedge_payup_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_posthedge_ticksawaycross_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_posthedge_timebasedcross_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
_checkbox_posthedge_sizebasedcross_CheckedChanged(_checkbox_quote_showqty, new EventArgs());
}
#endregion
#region UI -> Data
public ParsedUIData<SpreaderLegContract> get_data() {
SpreaderLegContract rv = new SpreaderLegContract();
try {
// top part
rv.security = _combobox_security.Text;
rv.qty = Int32.Parse(_textbox_leg_qty.Text);
rv.price_mult = Double.Parse(_textbox_leg_price_mult.Text);
rv.enable_quoting = _checkbox_leg_enablequoting.Checked;
rv.lean_qty_factor = Double.Parse(_textbox_leg_leanqtyfactor.Text);
rv.md_type = SpreaderLegContract.MDType.Merged;
// Quote
rv.quote_params = new SpreaderLegContract.QuoteParams();
rv.quote_params.qho_length = String.IsNullOrEmpty(_textbox_quote_qho_length.Text) ? 0 :
UInt32.Parse(_textbox_quote_qho_length.Text);
rv.quote_params.show_qty = null;
if (_checkbox_quote_showqty.Checked) {
rv.quote_params.show_qty = new SpreaderLegContract.QuoteParams.ShowQty();
rv.quote_params.show_qty.show_qty = UInt32.Parse(_textbox_quote_showqty_qty.Text);
}
rv.quote_params.throttle = null;
if (_checkbox_quote_throttle.Checked) {
rv.quote_params.throttle = new SpreaderLegContract.QuoteParams.Throttle();
rv.quote_params.throttle.inside_ticks = UInt32.Parse(_textbox_quote_throttle_insideticks.Text);
rv.quote_params.throttle.outside_ticks = UInt32.Parse(_textbox_quote_throttle_outsideticks.Text);
}
rv.quote_params.conditional = null;
if (_checkbox_quote_conditional.Checked) {
rv.quote_params.conditional = new SpreaderLegContract.QuoteParams.Conditional();
rv.quote_params.conditional.ticks = Int32.Parse(_textbox_quote_conditional_ticks.Text);
}
rv.quote_params.inside_market_distance = null;
if (_checkbox_quote_insidemarketdistance.Checked) {
rv.quote_params.inside_market_distance = new SpreaderLegContract.QuoteParams.InsideMarketDistance();
rv.quote_params.inside_market_distance.toward_distance =
UInt32.Parse(_textbox_quote_insidemarketdistance_towarddistance.Text);
}
//Pre-Hedge
rv.pre_hedge_params = new SpreaderLegContract.PreHedgeParams();
rv.pre_hedge_params.payless = null;
if (_checkbox_prehedge_payless.Checked) {
rv.pre_hedge_params.payless = new SpreaderLegContract.PreHedgeParams.PayLess();
rv.pre_hedge_params.payless.threshold = UInt32.Parse(_textbox_prehedge_payless_threshold.Text);
rv.pre_hedge_params.payless.payless_ticks =
UInt32.Parse(_textbox_prehedge_payless_paylessticks.Text);
}
rv.pre_hedge_params.payup = null;
if (_checkbox_prehedge_payup.Checked) {
rv.pre_hedge_params.payup = new SpreaderLegContract.PreHedgeParams.PayUp();
rv.pre_hedge_params.payup.threshold = UInt32.Parse(_textbox_prehedge_payup_threshold.Text);
rv.pre_hedge_params.payup.payup_ticks = UInt32.Parse(_textbox_prehedge_payup_payupticks.Text);
}
//Post-Hedge
rv.post_hedge_params = new SpreaderLegContract.PostHedgeParams();
rv.post_hedge_params.ticks_away_cross = null;
if (_checkbox_posthedge_ticksawaycross.Checked) {
rv.post_hedge_params.ticks_away_cross = new SpreaderLegContract.PostHedgeParams.TicksAwayCross();
rv.post_hedge_params.ticks_away_cross.threshold = UInt32.Parse(_textbox_posthedge_ticksawaycross_threshold.Text);
rv.post_hedge_params.ticks_away_cross.cross_ticks = UInt32.Parse(_textbox_posthedge_ticksawaycross_crossticks.Text);
}
rv.post_hedge_params.time_based_cross = null;
if (_checkbox_posthedge_timebasedcross.Checked) {
rv.post_hedge_params.time_based_cross = new SpreaderLegContract.PostHedgeParams.TimeBasedCross();
rv.post_hedge_params.time_based_cross.time_ms =
UInt32.Parse(_textbox_posthedge_timesbasedcross_timems.Text);
rv.post_hedge_params.time_based_cross.cross_ticks =
UInt32.Parse(_textbox_posthedge_timesbasedcross_crossticks.Text);
}
rv.post_hedge_params.size_based_cross = null;
if (_checkbox_posthedge_sizebasedcross.Checked) {
rv.post_hedge_params.size_based_cross = new SpreaderLegContract.PostHedgeParams.SizedBasedCross();
rv.post_hedge_params.size_based_cross.threshold = UInt32.Parse(_textbox_posthedge_sizebasedcross_threshold.Text);
rv.post_hedge_params.size_based_cross.cross_ticks = UInt32.Parse(_textbox_posthedge_sizebasedcross_crossticks.Text);
}
}
catch(Exception ex) {
return new ParsedUIData<SpreaderLegContract>(null, true, ex.Message);
}
return new ParsedUIData<SpreaderLegContract>(rv, false, String.Empty);
}
#endregion
public SpreaderLegContract get_contract() {
return null;
}
#region Checkbox Check Change Events
private void _checkbox_quote_showqty_CheckedChanged(object sender, EventArgs e) {
_textbox_quote_showqty_qty.Enabled = _checkbox_quote_showqty.Checked;
}
private void _checkbox_quote_throttle_CheckedChanged(object sender, EventArgs e) {
_textbox_quote_throttle_insideticks.Enabled = _checkbox_quote_throttle.Checked;
_textbox_quote_throttle_outsideticks.Enabled = _checkbox_quote_throttle.Checked;
}
private void _checkbox_quote_conditional_CheckedChanged(object sender, EventArgs e) {
_textbox_quote_conditional_ticks.Enabled = _checkbox_quote_conditional.Checked;
}
private void _checkbox_quote_insidemarketdistance_CheckedChanged(object sender, EventArgs e) {
_textbox_quote_insidemarketdistance_towarddistance.Enabled = _checkbox_quote_insidemarketdistance.Checked;
}
private void _checkbox_prehedge_payless_CheckedChanged(object sender, EventArgs e) {
_textbox_prehedge_payless_threshold.Enabled = _checkbox_prehedge_payless.Checked;
_textbox_prehedge_payless_paylessticks.Enabled = _checkbox_prehedge_payless.Checked;
}
private void _checkbox_prehedge_payup_CheckedChanged(object sender, EventArgs e) {
_textbox_prehedge_payup_threshold.Enabled = _checkbox_prehedge_payup.Checked;
_textbox_prehedge_payup_payupticks.Enabled = _checkbox_prehedge_payup.Checked;
}
private void _checkbox_posthedge_ticksawaycross_CheckedChanged(object sender, EventArgs e) {
_textbox_posthedge_ticksawaycross_threshold.Enabled = _checkbox_posthedge_ticksawaycross.Checked;
_textbox_posthedge_ticksawaycross_crossticks.Enabled = _checkbox_posthedge_ticksawaycross.Checked;
}
private void _checkbox_posthedge_timebasedcross_CheckedChanged(object sender, EventArgs e) {
_textbox_posthedge_timesbasedcross_timems.Enabled = _checkbox_posthedge_timebasedcross.Checked;
_textbox_posthedge_timesbasedcross_crossticks.Enabled = _checkbox_posthedge_timebasedcross.Checked;
}
private void _checkbox_posthedge_sizebasedcross_CheckedChanged(object sender, EventArgs e) {
_textbox_posthedge_sizebasedcross_threshold.Enabled = _checkbox_posthedge_sizebasedcross.Checked;
_textbox_posthedge_sizebasedcross_crossticks.Enabled = _checkbox_posthedge_sizebasedcross.Checked;
}
#endregion
}
}
@@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,152 @@
using System.Windows.Forms;
namespace SpreaderFrontEnd
{
partial class MainSpreaderForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this._button_ok = new System.Windows.Forms.Button();
this._button_cancel = new System.Windows.Forms.Button();
this._label_spreader_name = new System.Windows.Forms.Label();
this._textbox_spreader_name = new System.Windows.Forms.TextBox();
this._legcontrol1 = new SpreaderFrontEnd.LegControl();
this._legcontrol2 = new SpreaderFrontEnd.LegControl();
this._legcontrol3 = new SpreaderFrontEnd.LegControl();
this._legcontrol4 = new SpreaderFrontEnd.LegControl();
this._legcontrol5 = new SpreaderFrontEnd.LegControl();
this.SuspendLayout();
//
// _button_ok
//
this._button_ok.Location = new System.Drawing.Point(1231, 1306);
this._button_ok.Name = "_button_ok";
this._button_ok.Size = new System.Drawing.Size(120, 33);
this._button_ok.TabIndex = 4;
this._button_ok.Text = "OK";
this._button_ok.UseVisualStyleBackColor = false;
this._button_ok.Click += new System.EventHandler(this._button_ok_Click);
//
// _button_cancel
//
this._button_cancel.Location = new System.Drawing.Point(1380, 1306);
this._button_cancel.Name = "_button_cancel";
this._button_cancel.Size = new System.Drawing.Size(121, 33);
this._button_cancel.TabIndex = 5;
this._button_cancel.Text = "Cancel";
this._button_cancel.UseVisualStyleBackColor = false;
this._button_cancel.Click += new System.EventHandler(this._button_cancel_Click);
//
// _label_spreader_name
//
this._label_spreader_name.AutoSize = true;
this._label_spreader_name.Location = new System.Drawing.Point(22, 28);
this._label_spreader_name.Name = "_label_spreader_name";
this._label_spreader_name.Size = new System.Drawing.Size(88, 15);
this._label_spreader_name.TabIndex = 6;
this._label_spreader_name.Text = "Spreader Name";
//
// _textbox_spreader_name
//
this._textbox_spreader_name.Location = new System.Drawing.Point(116, 25);
this._textbox_spreader_name.Name = "_textbox_spreader_name";
this._textbox_spreader_name.Size = new System.Drawing.Size(343, 23);
this._textbox_spreader_name.TabIndex = 0;
//
// _legcontrol1
//
this._legcontrol1.BackColor = System.Drawing.Color.White;
this._legcontrol1.Location = new System.Drawing.Point(22, 67);
this._legcontrol1.Name = "_legcontrol1";
this._legcontrol1.Size = new System.Drawing.Size(291, 1220);
this._legcontrol1.TabIndex = 1;
//
// _legcontrol2
//
this._legcontrol2.BackColor = System.Drawing.Color.White;
this._legcontrol2.Location = new System.Drawing.Point(319, 67);
this._legcontrol2.Name = "_legcontrol2";
this._legcontrol2.Size = new System.Drawing.Size(291, 1220);
this._legcontrol2.TabIndex = 2;
//
// _legcontrol3
//
this._legcontrol3.BackColor = System.Drawing.Color.White;
this._legcontrol3.Location = new System.Drawing.Point(616, 67);
this._legcontrol3.Name = "_legcontrol3";
this._legcontrol3.Size = new System.Drawing.Size(291, 1220);
this._legcontrol3.TabIndex = 3;
//
// _legcontrol4
//
this._legcontrol4.BackColor = System.Drawing.Color.White;
this._legcontrol4.Location = new System.Drawing.Point(913, 67);
this._legcontrol4.Name = "_legcontrol4";
this._legcontrol4.Size = new System.Drawing.Size(291, 1220);
this._legcontrol4.TabIndex = 4;
//
// _legcontrol5
//
this._legcontrol5.BackColor = System.Drawing.Color.White;
this._legcontrol5.Location = new System.Drawing.Point(1210, 67);
this._legcontrol5.Name = "_legcontrol5";
this._legcontrol5.Size = new System.Drawing.Size(291, 1220);
this._legcontrol5.TabIndex = 5;
//
// MainSpreaderForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1517, 1363);
this.Controls.Add(this._legcontrol5);
this.Controls.Add(this._legcontrol4);
this.Controls.Add(this._legcontrol3);
this.Controls.Add(this._legcontrol2);
this.Controls.Add(this._legcontrol1);
this.Controls.Add(this._textbox_spreader_name);
this.Controls.Add(this._label_spreader_name);
this.Controls.Add(this._button_cancel);
this.Controls.Add(this._button_ok);
this.Name = "MainSpreaderForm";
this.Text = "MainSpreaderForm";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private Button _button_ok;
private Button _button_cancel;
private Label _label_spreader_name;
private TextBox _textbox_spreader_name;
private LegControl _legcontrol1;
private LegControl _legcontrol2;
private LegControl _legcontrol3;
private LegControl _legcontrol4;
private LegControl _legcontrol5;
}
}
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SpreaderFrontEnd {
// This is the main UI widget. It is passed a list of securities and a SpreaderContract.
// The SpreaderContract can be empty (which will be the case when creating a new spreader).
// It has 3 public facing members (other than the constructor),
// 2 events that tell whether OK or Cancel was hit, respectively,
// and get_spreader_contract that returns a ParsedUIData<SpreaderContract>
public partial class MainSpreaderForm : Form {
private IEnumerable<LegControl> _leg_controls;
public Action on_OK = () => { };
public Action on_cancel = () => { };
private readonly IEnumerable<string> _securities;
private SpreaderContract _spreader_contract;
public MainSpreaderForm(IEnumerable<string> securities,
SpreaderContract spreader_contract)
: base() {
InitializeComponent();
_leg_controls = new LegControl[] { _legcontrol1, _legcontrol2, _legcontrol3, _legcontrol4, _legcontrol5 };
_securities = securities;
System.Diagnostics.Debug.Assert(spreader_contract != null);
// System.Diagnostics.Debug.Assert(spreader_contract.spread_legs.Count() == SpreaderContract.max_nlegs);
_spreader_contract = spreader_contract;
_textbox_spreader_name.Text = _spreader_contract.name;
for (var i = 0; i < _leg_controls.Count(); i++) {
SpreaderLegContract? lc = i < _spreader_contract.spread_legs.Count() ?
_spreader_contract.spread_legs.ElementAt(i) : null;
_leg_controls.ElementAt(i).initialize(securities, lc);
}
}
public ParsedUIData<SpreaderContract> get_spreader_contract() {
if (String.IsNullOrEmpty(_textbox_spreader_name.Text)) {
return new ParsedUIData<SpreaderContract>(null, true, "Spreader name is not set");
}
List<SpreaderLegContract> leg_contracts = new List<SpreaderLegContract>();
uint i = 0;
foreach (LegControl lc in _leg_controls) {
i++;
var leg_res = lc.get_data();
if (leg_res.is_error) {
return new ParsedUIData<SpreaderContract>(null, true, $"Leg: {i} is not set correctly");
}
leg_contracts.Add(leg_res.ui_data);
}
IEnumerable<SpreaderLegContract> leg_contracts_rv =
leg_contracts.Where(l => !String.IsNullOrEmpty(l.security));
if (leg_contracts_rv.Count() <= 1) {
return new ParsedUIData<SpreaderContract>(
null, true, "Spreader needs at least 2 legs");
}
// check the number of legs
return new ParsedUIData<SpreaderContract>(
new SpreaderContract(_textbox_spreader_name.Text, leg_contracts_rv), false, String.Empty);
}
private void _button_ok_Click(object sender, EventArgs e) {
ParsedUIData<SpreaderContract> ui_data = get_spreader_contract();
if (ui_data.is_error) {
string err_txt = $"The following error happened \n{ui_data.error_txt}";
System.Windows.Forms.MessageBox.Show(err_txt, "Spreader Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
on_OK();
}
private void _button_cancel_Click(object sender, EventArgs e) {
on_cancel();
}
}
}
@@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,20 @@
namespace SpreaderFrontEnd {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class ParsedUIData<T> {
public readonly T ui_data;
public readonly bool is_error;
public readonly string error_txt;
public ParsedUIData(T ui_data, bool is_error, string error_txt) {
this.ui_data = ui_data;
this.is_error = is_error;
this.error_txt = error_txt;
}
}
}
@@ -0,0 +1,18 @@
using System;
using System.Windows.Forms;
namespace SpreaderFrontEnd {
internal static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
SyntheticBookTest.run();
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new TestForm());
}
}
}
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SpreaderFrontEnd
{
[Serializable]
// Represents a spreader contract (anologous ot the protobuf on the C++ side)
// We could have generated managed wrappers from the protobuf, but we did not want
// to make your build process complicated hence opted for this class.
// It is quite simply a wrapper around an enumeration of SpreaderLegContract
public class SpreaderContract
{
public static uint max_nlegs = 5;
public string name = String.Empty;
public IList<SpreaderLegContract> spread_legs = new List<SpreaderLegContract>();
public SpreaderContract(string name, IEnumerable<SpreaderLegContract> spread_legs)
{
this.name = name;
this.spread_legs = spread_legs.ToList();
}
public static SpreaderContract empty
{
get
{
return new SpreaderContract("UNNAMED",
Enumerable.Repeat<SpreaderLegContract>(new SpreaderLegContract(), 5));
}
}
}
}
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<LanguageVersion>7</LanguageVersion>
</PropertyGroup>
</Project>
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SpreaderFrontEnd
{
[Serializable]
// Represents a single leg of the spreader. It is made up of
// 1. a main section consisting of the security, qty, price mult etc
// 2. Quote parameters
// 3. Pre-Hedge parameters
// 4. Post-Hedge parameters
// It maps pretty directly to the UI (LegControl)
public class SpreaderLegContract
{
public enum MDType {
Direct = 0,
Merged = 1,
}
public string security = String.Empty;
public int qty = 1;
public double price_mult = 1;
public bool enable_quoting = false;
public double lean_qty_factor = 1;
public MDType md_type = MDType.Direct;
public QuoteParams quote_params = new QuoteParams();
public PreHedgeParams pre_hedge_params = new PreHedgeParams();
public PostHedgeParams post_hedge_params = new PostHedgeParams();
public class QuoteParams
{
public class ShowQty {
public UInt32 show_qty = 1;
}
public class Throttle {
public UInt32 inside_ticks = 0;
public UInt32 outside_ticks = 0;
}
public class Conditional {
public Int32 ticks = 0;
}
public class InsideMarketDistance {
public UInt32 toward_distance = 0;
}
public UInt32 qho_length = 0;
public ShowQty? show_qty = null;
public Throttle? throttle = null;
public Conditional? conditional = null;
public InsideMarketDistance? inside_market_distance = null;
}
public class PreHedgeParams
{
public class PayLess {
public UInt32 threshold = 0;
public UInt32 payless_ticks = 0;
}
public class PayUp
{
public UInt32 threshold = 0;
public UInt32 payup_ticks = 0;
}
public PayLess? payless = null;
public PayUp? payup = null;
}
public class PostHedgeParams
{
public class TicksAwayCross {
public UInt32 threshold = 0;
public UInt32 cross_ticks = 0;
}
public class TimeBasedCross {
public UInt32 time_ms = 0;
public UInt32 cross_ticks = 0;
}
public class SizedBasedCross {
public UInt32 threshold = 0;
public UInt32 cross_ticks = 0;
}
public TicksAwayCross? ticks_away_cross = null;
public TimeBasedCross? time_based_cross = null;
public SizedBasedCross? size_based_cross = null;
}
}
}
+79
View File
@@ -0,0 +1,79 @@
using System.Windows.Forms;
namespace SpreaderFrontEnd
{
partial class TestForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this._button_launch_new = new System.Windows.Forms.Button();
this._button_load_existing = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// _button_launch_new
//
this._button_launch_new.Location = new System.Drawing.Point(96, 46);
this._button_launch_new.Name = "_button_launch_new";
this._button_launch_new.Size = new System.Drawing.Size(169, 26);
this._button_launch_new.TabIndex = 0;
this._button_launch_new.Text = "Launch New";
this._button_launch_new.UseVisualStyleBackColor = true;
this._button_launch_new.Click += new System.EventHandler(this._button_launch_new_Click);
//
// _button_load_existing
//
this._button_load_existing.Location = new System.Drawing.Point(96, 114);
this._button_load_existing.Name = "_button_load_existing";
this._button_load_existing.Size = new System.Drawing.Size(169, 26);
this._button_load_existing.TabIndex = 1;
this._button_load_existing.Text = "Load Existing";
this._button_load_existing.UseVisualStyleBackColor = true;
this._button_load_existing.Click += new System.EventHandler(this._button_load_existing_Click);
//
// TestForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(371, 213);
this.Controls.Add(this._button_load_existing);
this.Controls.Add(this._button_launch_new);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "TestForm";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.Text = "Test Launcher";
this.ResumeLayout(false);
}
#endregion
private Button _button_launch_new;
private Button _button_load_existing;
}
}
@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace SpreaderFrontEnd {
// Test class that demostrates how to use the MainSpreaderForm.
// It has 2 buttons. "Launch New" launches a brand new spreader (empty UI)
// while "Launch Existing" loads the MainSpreaderForm with an existing
// spreader (hard coded arbitrary values)
public partial class TestForm : Form {
private IEnumerable<string> _securities = new string[] {
"ZCG23",
"ZCH23",
"ZCJ23",
"ZCL23",
"ZCM23"
};
public TestForm() {
InitializeComponent();
}
private void _button_launch_new_Click(object sender, EventArgs e) {
_show_form(SpreaderContract.empty);
}
private void _button_load_existing_Click(object sender, EventArgs e) {
var sc = _generate_test_contract();
_show_form(sc);
}
private void _show_form(SpreaderContract spreader_contract) {
MainSpreaderForm f = new MainSpreaderForm(_securities, spreader_contract);
f.on_OK = () => {
MessageBox.Show("Received OK", "OK", MessageBoxButtons.OK, MessageBoxIcon.Information);
f.Close();
};
f.on_cancel = () => {
MessageBox.Show("Received Cancel", "Cancel", MessageBoxButtons.OK, MessageBoxIcon.Warning);
f.Close();
};
f.ShowDialog();
}
private SpreaderContract _generate_test_contract() {
List<SpreaderLegContract> lcs = new List<SpreaderLegContract>();
for (uint i = 0; i < 3; i++) {
SpreaderLegContract lc = _generate_test_leg_contract(i);
lcs.Add(lc);
}
SpreaderContract sc = new SpreaderContract("TEST SPREADER", lcs);
return sc;
}
private SpreaderLegContract _generate_test_leg_contract(uint idx) {
SpreaderLegContract rv = new SpreaderLegContract();
rv.security = _securities.ElementAt(0);
rv.qty = 1;
rv.price_mult = 1;
rv.enable_quoting = true;
rv.lean_qty_factor = 2;
rv.md_type = SpreaderLegContract.MDType.Merged;
// quote
rv.quote_params = new SpreaderLegContract.QuoteParams();
rv.quote_params.qho_length = 0;
rv.quote_params.show_qty = new SpreaderLegContract.QuoteParams.ShowQty();
rv.quote_params.show_qty.show_qty = 10;
rv.quote_params.throttle = new SpreaderLegContract.QuoteParams.Throttle();
rv.quote_params.throttle.inside_ticks = 3;
rv.quote_params.throttle.outside_ticks = 2;
// pre hedge
rv.pre_hedge_params = new SpreaderLegContract.PreHedgeParams();
rv.pre_hedge_params.payless = new SpreaderLegContract.PreHedgeParams.PayLess();
rv.pre_hedge_params.payless.threshold = 1000;
rv.pre_hedge_params.payless.payless_ticks = 7;
rv.pre_hedge_params.payup = new SpreaderLegContract.PreHedgeParams.PayUp();
rv.pre_hedge_params.payup.threshold = 500;
rv.pre_hedge_params.payup.payup_ticks = 12;
// post hedge
rv.post_hedge_params = new SpreaderLegContract.PostHedgeParams();
rv.post_hedge_params.ticks_away_cross = new SpreaderLegContract.PostHedgeParams.TicksAwayCross();
rv.post_hedge_params.ticks_away_cross.threshold = 10;
rv.post_hedge_params.ticks_away_cross.cross_ticks = 3;
rv.post_hedge_params.time_based_cross = new SpreaderLegContract.PostHedgeParams.TimeBasedCross();
rv.post_hedge_params.time_based_cross.time_ms = 20;
rv.post_hedge_params.time_based_cross.cross_ticks = 5;
return rv;
}
}
};
@@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,230 @@
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
namespace SpreaderFrontEnd {
public static class SyntheticBookTest {
/// <summary>
/// Run synthetic book computation tests
/// </summary>
public static int run() {
// Seed the test with a standard butterfly spread. Leg size multipliers will be applied to
// each leg to generate more variations to test.
var legs = new List<SpreaderLegContract> {
new SpreaderLegContract() {
security = "Leg1Sec",
qty = 1
},
new SpreaderLegContract() {
security = "Leg2Sec",
qty = -2
},
new SpreaderLegContract() {
security = "Leg3Sec",
qty = 1
}
};
var leg_multipliers = new List<int> { 1, -1, 2, -2, 3, -3 };
var contract = new SpreaderContract("Test", legs);
// Define a book (seed) for each leg. Quantities will be added to each price level for each
// leg's book to generate more variations to test.
var leg1_book = new Book(
bids: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 3, qty: 10),
new PriceLevel(price: 2, qty: 4),
new PriceLevel(price: 1, qty: 6)
}),
asks: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 4, qty: 5),
new PriceLevel(price: 5, qty: 7),
new PriceLevel(price: 6, qty: 8)
}));
var leg2_book = new Book(
bids: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 3, qty: 1),
new PriceLevel(price: 2, qty: 7),
new PriceLevel(price: 1, qty: 2)
}),
asks: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 4, qty: 3),
new PriceLevel(price: 5, qty: 3),
new PriceLevel(price: 6, qty: 5)
}));
var leg3_book = new Book(
bids: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 3, qty: 2),
new PriceLevel(price: 2, qty: 1),
new PriceLevel(price: 1, qty: 8)
}),
asks: new BookSide(levels: new List<PriceLevel> {
new PriceLevel(price: 4, qty: 4),
new PriceLevel(price: 5, qty: 3),
new PriceLevel(price: 6, qty: 4)
}));
var level_qty_additions = new List<uint> { 1, 2, 3, 4 };
var leg_books = new List<Book> { leg1_book, leg2_book, leg3_book };
for (int i = 0; i < leg_multipliers.Count; i++) {
var leg_mult = leg_multipliers[i];
for (int j = 0; j < contract.spread_legs.Count; j++) {
// Apply leg mult
contract.spread_legs[j].qty *= leg_mult;
foreach (var lqa in level_qty_additions) {
foreach(var lb in leg_books) {
// Apply qty addition to bid-levels
for (int level_idx = 0; level_idx < lb.bids.levels.Count; level_idx++) {
var orig_level = lb.bids.levels[level_idx];
lb.bids.levels[level_idx] = orig_level.add_qty(lqa);
run(leg_books, contract);
// Subtract the qty that was just added so each qty addition is applied to
// the original level
lb.bids.levels[level_idx] = lb.bids.levels[level_idx].subtract_qty(lqa);
}
// Apply qty additions to ask-levels
for (int level_idx = 0; level_idx < lb.asks.levels.Count; level_idx++) {
var orig_level = lb.asks.levels[level_idx];
lb.asks.levels[level_idx] = orig_level.add_qty(lqa);
run(leg_books, contract);
// Subtract the qty that was just added so each qty addition is applied to
// the original level
lb.asks.levels[level_idx] = lb.asks.levels[level_idx].subtract_qty(lqa);
}
}
}
// Divide by leg_mult so the each mult is applied to the original leg
contract.spread_legs[j].qty /= leg_mult;
}
}
return 0;
}
public static void run(List<Book> leg_books, SpreaderContract contract) {
var synth_book = SpreaderBookCalculator.compute_spreader_book(contract, leg_books);
for (int i = 0; i < contract.spread_legs.Count; i++) {
Console.WriteLine($"Leg{i} (qty {contract.spread_legs[i].qty}): {leg_books[i]}");
}
Console.WriteLine($"Synthetic Book: {synth_book}");
var leg_book_tups = _to_leg_book_tuples(leg_books, contract);
var expected_book = _compute_synth_book(leg_book_tups);
Console.WriteLine($"Expected Book: {expected_book}");
Debug.Assert(expected_book.Equals(synth_book));
}
static List<Tuple<Book, int>> _to_leg_book_tuples(List<Book> leg_books, SpreaderContract contract) {
Debug.Assert(leg_books.Count == contract.spread_legs.Count);
var rv = new List<Tuple<Book, int>>();
for (int i = 0; i < leg_books.Count; i++) {
rv.Add(Tuple.Create(leg_books[i], contract.spread_legs[i].qty));
}
return rv;
}
static List<Tuple<BookSide, int>> _to_leg_book_side_tuples(List<Tuple<Book, int>> leg_books, bool is_bid) {
var leg_book_tups = new List<Tuple<BookSide, int>>();
for (int i = 0; i < leg_books.Count; i++) {
var leg_size = leg_books[i].Item2;
var leg_book = leg_books[i].Item1;
var is_buy_leg = leg_size > 0;
var leg_book_side = is_buy_leg == is_bid ? leg_book.bids : leg_book.asks;
leg_book_tups.Add(Tuple.Create(leg_book_side, leg_size));
}
return leg_book_tups;
}
static Book _compute_synth_book(List<Tuple<Book, int>> leg_books) {
var leg_bids = _to_leg_book_side_tuples(leg_books, true);
var leg_asks = _to_leg_book_side_tuples(leg_books, false);
var synth_bids = _compute_synth_book_side(leg_bids);
var synth_asks = _compute_synth_book_side(leg_asks);
return new Book(synth_bids, synth_asks);
}
// <summary>
// Computes the synthetic book in a simple/unoptimized way, to ensure correctness. Books
// generated by the 'optimized' routine, which will be used in practice, should match those
// generated by this one.
// </summary>
static BookSide _compute_synth_book_side(IEnumerable<Tuple<BookSide, int>> leg_books) {
// Clone the books so we can mutate them without changing the input 'leg_books'
var leg_books_list = leg_books.Select(lb => Tuple.Create(lb.Item1.Clone(), lb.Item2)).ToList();
var levels = new List<PriceLevel>();
var top_level = _get_top_level(leg_books_list);
while (top_level.qty > 0) {
levels.Add(top_level);
foreach (var lb in leg_books_list) {
_remove_qty_from_top(lb.Item1, (int)(top_level.qty * Math.Abs(lb.Item2)));
}
top_level = _get_top_level(leg_books_list);
}
return new BookSide(levels);
}
static PriceLevel _get_top_level(IEnumerable<Tuple<BookSide, int>> leg_books) {
var leg_sizes = leg_books.Select(lb => lb.Item2).ToList();
var top_levels = leg_books.Select(_get_top_level).ToList();
var qty = top_levels.Select(l => l.qty).Min();
if (qty == 0) {
return PriceLevel.empty;
}
double price = 0;
for (int i = 0; i < top_levels.Count; i++) {
var leg_price = top_levels[i].price;
var leg_size = leg_sizes[i];
if (leg_size < 0) {
price -= leg_price;
} else {
price += leg_price;
}
}
return new PriceLevel(price, qty);
}
static PriceLevel _get_top_level(Tuple<BookSide, int> leg_book) {
return _get_top_level(leg_book.Item1, leg_book.Item2);
}
static PriceLevel _get_top_level(BookSide book, int leg_size) {
if (book.levels.Count == 0) {
return PriceLevel.empty;
}
var first_level = book.levels.First();
var abs_leg_size = Math.Abs(leg_size);
if (first_level.qty >= abs_leg_size) {
return new PriceLevel(first_level.price * abs_leg_size, (uint)(first_level.qty / abs_leg_size));
}
double price = first_level.qty * first_level.price;
var qty_rem = abs_leg_size - first_level.qty;
for (int i = 1; i < book.levels.Count; i++) {
var level = book.levels[i];
if (level.qty >= qty_rem) {
price += qty_rem * level.price;
return new PriceLevel(price, 1);
}
price += level.qty * level.price;
qty_rem -= level.qty;
}
return PriceLevel.empty;
}
/// <summary>
/// Removes the specified quantity from the top of the book
/// </summary>
static void _remove_qty_from_top(BookSide book, int qty) {
var subtracted_qty = 0;
while (subtracted_qty < qty && book.levels.Count > 0) {
var first_level = book.levels[0];
var qty_to_subtract = qty - subtracted_qty;
if (first_level.qty > qty_to_subtract) {
first_level = first_level.subtract_qty((uint)qty_to_subtract);
book.levels[0] = first_level;
return;
}
book.levels.RemoveAt(0);
subtracted_qty += (int)first_level.qty;
}
}
}
}
@@ -0,0 +1,78 @@
using System;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
namespace SpreaderFrontEnd
{
public class Utils
{
public static void bin_serialize<T>(T t, Stream str)
{
#pragma warning disable SYSLIB0011
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(str, t);
#pragma warning restore SYSLIB0011
}
public static T bin_deserialize<T>(Stream str)
{
#pragma warning disable SYSLIB0011
BinaryFormatter bf = new BinaryFormatter();
T rv = (T)bf.Deserialize(str);
#pragma warning restore SYSLIB0011
return rv;
}
public static T? basic_deep_clone<T>(T t)
{
try
{
MemoryStream str = new MemoryStream();
bin_serialize(t, str);
str.Position = 0;
return bin_deserialize<T>(str);
}
catch
{
return default(T);
}
}
public static object? CloneObject(object objSource)
{
//step : 1 Get the type of source object and create a new instance of that type
Type typeSource = objSource.GetType();
object? objTarget = Activator.CreateInstance(typeSource);
//Step2 : Get all the properties of source object type
PropertyInfo[] propertyInfo = typeSource.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
//Step : 3 Assign all source property to taget object 's properties
foreach (PropertyInfo property in propertyInfo)
{
//Check whether property can be written to
if (property.CanWrite)
{
//Step : 4 check whether property type is value type, enum or string type
if (property.PropertyType.IsValueType || property.PropertyType.IsEnum || property.PropertyType.Equals(typeof(System.String)))
{
property.SetValue(objTarget, property.GetValue(objSource, null), null);
}
//else property type is object/complex types, so need to recursively call this method until the end of the tree is reached
else
{
object? objPropertyValue = property.GetValue(objSource, null);
if (objPropertyValue == null)
{
property.SetValue(objTarget, null, null);
}
else
{
property.SetValue(objTarget, CloneObject(objPropertyValue), null);
}
}
}
}
return objTarget;
}
}
}
@@ -0,0 +1,23 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v6.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v6.0": {
"SpreaderFrontEnd/1.0.0": {
"runtime": {
"SpreaderFrontEnd.dll": {}
}
}
}
},
"libraries": {
"SpreaderFrontEnd/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}
@@ -0,0 +1,15 @@
{
"runtimeOptions": {
"tfm": "net6.0",
"frameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "6.0.0"
},
{
"name": "Microsoft.WindowsDesktop.App",
"version": "6.0.0"
}
]
}
}
+1 -3
View File
@@ -46,7 +46,6 @@ function setup_build
assert_dir $repo_root
assert_dir $build_root
set compiler "$argv[1]"
set c_compiler (which cc)
set build_type "$argv[2]"
if test \( -z "$build_type" \) -o \( \( "$build_type" != debug \) -a \( "$build_type" != release \) \)
@@ -60,7 +59,6 @@ function setup_build
else
# set compiler_arg "/usr/lib/ccache/clang++"
set compiler_arg "clang++"
set c_compiler (which clang)
end
else if test "$build_type" = release
set build_type_arg Release
@@ -87,7 +85,7 @@ function setup_build
rm -rf "$build_dest"
mkdir -p "$build_dest"
cd "$build_dest"
cmake -G Ninja -DCMAKE_BUILD_TYPE=$build_type_arg -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_C_COMPILER=$c_compiler -DCMAKE_CXX_COMPILER=$compiler_arg $repo_root
cmake -G Ninja -DCMAKE_BUILD_TYPE=$build_type_arg -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_CXX_COMPILER=$compiler_arg $repo_root
end
# The while loop below removes arguments (via shift) as it parses them.
File renamed without changes.
@@ -1,941 +0,0 @@
{
"$schema": "vscode://schemas/color-theme",
"type": "dark",
"colors": {
"activityBar.background": "#111111",
"activityBar.border": "#111111",
"activityBar.foreground": "#888888",
"activityBarBadge.background": "#88cc44",
"activityBarBadge.foreground": "#222222",
"badge.background": "#88cc44",
"badge.foreground": "#222222",
"button.background": "#333333",
"button.foreground": "#888888",
"button.hoverBackground": "#222222",
"debugExceptionWidget.background": "#333333",
"debugExceptionWidget.border": "#222222",
"debugToolBar.background": "#111111",
"diffEditor.insertedTextBackground": "#ffdd440c",
"diffEditor.insertedTextBorder": "#ffdd44",
"diffEditor.removedTextBackground": "#88bbff0c",
"diffEditor.removedTextBorder": "#88bbff",
"dropdown.background": "#222222",
"dropdown.border": "#222222",
"dropdown.foreground": "#888888",
"editor.background": "#222222",
"editor.findMatchBackground": "#44446655",
"editor.findMatchHighlightBackground": "#444466aa",
"editor.foreground": "#ffffff",
"editor.hoverHighlightBackground": "#44446655",
"editor.inactiveSelectionBackground": "#44446655",
"editor.lineHighlightBackground": "#00000066",
"editor.lineHighlightBorder": "#00000000",
"editor.rangeHighlightBackground": "#333333",
"editor.selectionBackground": "#444466",
"editor.selectionHighlightBackground": "#44446655",
"editor.wordHighlightBackground": "#44446655",
"editor.wordHighlightStrongBackground": "#44446655",
"editorBracketMatch.background": "#222222",
"editorBracketMatch.border": "#666666",
"editorCodeLens.foreground": "#666666",
"editorCursor.foreground": "#ffffff",
"editorError.foreground": "#ee5500",
"editorGroup.border": "#111111",
"editorGroup.dropBackground": "#111111bb",
"editorGroupHeader.noTabsBackground": "#111111",
"editorGroupHeader.tabsBackground": "#111111",
"editorGroupHeader.tabsBorder": "#222222",
"editorGutter.addedBackground": "#ffdd44",
"editorGutter.background": "#222222",
"editorGutter.deletedBackground": "#88bbff",
"editorGutter.modifiedBackground": "#88bbff",
"editorHoverWidget.background": "#333333",
"editorHoverWidget.border": "#222222",
"editorIndentGuide.background": "#333333",
"editorLineNumber.foreground": "#555555",
"editorLink.activeForeground": "#bba0ff",
"editorMarkerNavigation.background": "#333333",
"editorMarkerNavigationError.background": "#88bbff",
"editorMarkerNavigationWarning.background": "#88bbff",
"editorOverviewRuler.addedForeground": "#ffdd44",
"editorOverviewRuler.border": "#222222",
"editorOverviewRuler.currentContentForeground": "#333333",
"editorOverviewRuler.deletedForeground": "#88bbff",
"editorOverviewRuler.errorForeground": "#88bbff",
"editorOverviewRuler.findMatchForeground": "#555555",
"editorOverviewRuler.incomingContentForeground": "#333333",
"editorOverviewRuler.infoForeground": "#bba0ff",
"editorOverviewRuler.modifiedForeground": "#88bbff",
"editorOverviewRuler.rangeHighlightForeground": "#333333",
"editorOverviewRuler.selectionHighlightForeground": "#555555",
"editorOverviewRuler.warningForeground": "#88bbff",
"editorOverviewRuler.wordHighlightForeground": "#333333",
"editorOverviewRuler.wordHighlightStrongForeground": "#555555",
"editorRuler.foreground": "#ffffff",
"editorSuggestWidget.background": "#333333",
"editorSuggestWidget.border": "#333333",
"editorSuggestWidget.foreground": "#888888",
"editorSuggestWidget.highlightForeground": "#ffffff",
"editorSuggestWidget.selectedBackground": "#666666",
"editorWarning.border": "#00000000",
"editorWarning.foreground": "#88bbff",
"editorWhitespace.foreground": "#333333",
"editorWidget.background": "#333333",
"editorWidget.border": "#333333",
"errorForeground": "#88bbff",
"extensionButton.prominentBackground": "#333333",
"extensionButton.prominentForeground": "#ffffff",
"extensionButton.prominentHoverBackground": "#555555",
"focusBorder": "#666666",
"foreground": "#ffffff",
"gitDecoration.modifiedResourceForeground": "#cccccc",
"gitDecoration.untrackedResourceForeground": "#cccccc",
"input.background": "#333333",
"input.border": "#333333",
"input.foreground": "#ffffff",
"input.placeholderForeground": "#555555",
"inputOption.activeBorder": "#555555",
"inputValidation.errorBackground": "#333333",
"inputValidation.errorBorder": "#88bbff",
"inputValidation.infoBackground": "#333333",
"inputValidation.infoBorder": "#bba0ff",
"inputValidation.warningBackground": "#333333",
"inputValidation.warningBorder": "#88bbff",
"list.activeSelectionBackground": "#111111",
"list.activeSelectionForeground": "#ffffff",
"list.dropBackground": "#111111bf",
"list.focusBackground": "#222222",
"list.focusForeground": "#ffffff",
"list.highlightForeground": "#ffffff",
"list.hoverBackground": "#333333",
"list.hoverForeground": "#ffffff",
"list.inactiveSelectionBackground": "#000000",
"list.inactiveSelectionForeground": "#ffffff",
"menu.background": "#333333",
"menu.foreground": "#ffffff",
"merge.border": "#222222",
"merge.currentContentBackground": "#333333",
"merge.currentHeaderBackground": "#555555",
"merge.incomingContentBackground": "#555555",
"merge.incomingHeaderBackground": "#666666",
"panel.background": "#111111",
"panel.border": "#111111",
"panelTitle.activeBorder": "#ffffff",
"panelTitle.activeForeground": "#ffffff",
"panelTitle.inactiveForeground": "#888888",
"peekView.border": "#222222",
"peekViewEditor.background": "#333333",
"peekViewEditor.matchHighlightBackground": "#555555",
"peekViewEditorGutter.background": "#333333",
"peekViewResult.background": "#333333",
"peekViewResult.fileForeground": "#888888",
"peekViewResult.lineForeground": "#888888",
"peekViewResult.matchHighlightBackground": "#555555",
"peekViewResult.selectionBackground": "#333333",
"peekViewResult.selectionForeground": "#ffffff",
"peekViewTitle.background": "#333333",
"peekViewTitleDescription.foreground": "#888888",
"peekViewTitleLabel.foreground": "#ffffff",
"pickerGroup.border": "#222222",
"pickerGroup.foreground": "#555555",
"progressBar.background": "#333333",
"scrollbar.shadow": "#191919",
"scrollbarSlider.activeBackground": "#ffffff12",
"scrollbarSlider.background": "#ffffff12",
"scrollbarSlider.hoverBackground": "#ffffff12",
"selection.background": "#2255aa",
"sideBar.background": "#111111",
"sideBar.border": "#111111",
"sideBar.foreground": "#888888",
"sideBarSectionHeader.background": "#111111",
"sideBarSectionHeader.foreground": "#666666",
"sideBarTitle.foreground": "#555555",
"statusBar.background": "#111111",
"statusBar.border": "#111111",
"statusBar.debuggingBackground": "#666666",
"statusBar.debuggingForeground": "#ffffff",
"statusBar.foreground": "#666666",
"statusBar.noFolderBackground": "#111111",
"statusBar.noFolderForeground": "#666666",
"statusBarItem.activeBackground": "#222222",
"statusBarItem.hoverBackground": "#222222",
"statusBarItem.prominentBackground": "#333333",
"statusBarItem.prominentHoverBackground": "#444444",
"tab.activeBackground": "#222222",
"tab.border": "#111111",
"tab.inactiveBackground": "#111111",
"tab.inactiveForeground": "#888888",
"tab.unfocusedActiveBorder": "#888888",
"tab.unfocusedActiveForeground": "#888888",
"tab.unfocusedInactiveForeground": "#888888",
"terminal.ansiBlack": "#333333",
"terminal.ansiBlue": "#88bbff",
"terminal.ansiBrightBlack": "#666666",
"terminal.ansiBrightBlue": "#88bbff",
"terminal.ansiBrightCyan": "#bba0ff",
"terminal.ansiBrightGreen": "#ffdd44",
"terminal.ansiBrightMagenta": "#88bbff",
"terminal.ansiBrightRed": "#88bbff",
"terminal.ansiBrightWhite": "#ffffff",
"terminal.ansiBrightYellow": "#88cc44",
"terminal.ansiCyan": "#bba0ff",
"terminal.ansiGreen": "#ffdd44",
"terminal.ansiMagenta": "#88bbff",
"terminal.ansiRed": "#88bbff",
"terminal.ansiWhite": "#ffffff",
"terminal.ansiYellow": "#88cc44",
"terminal.background": "#151515",
"terminal.foreground": "#ffffff",
"titleBar.activeBackground": "#111111",
"titleBar.activeForeground": "#888888",
"titleBar.inactiveBackground": "#111111",
"titleBar.inactiveForeground": "#555555",
"walkThrough.embeddedEditorBackground": "#111111",
"widget.shadow": "#111111",
//"activityBar.activeBorder": "#888888",
//"activityBar.dropBorder": "#888888",
//"activityBar.inactiveForeground": "#88888866",
//"banner.background": "#111111",
//"banner.foreground": "#ffffff",
//"banner.iconForeground": "#3794ff",
//"bookmarks.lineBackground": "#00000000",
//"bookmarks.lineBorder": "#00000000",
//"bookmarks.overviewRuler": "#157efb88",
//"breadcrumb.activeSelectionForeground": "#ffffff",
//"breadcrumb.background": "#222222",
//"breadcrumb.focusForeground": "#ffffff",
//"breadcrumb.foreground": "#ffffffcc",
//"breadcrumbPicker.background": "#333333",
//"button.secondaryBackground": "#3a3d41",
//"button.secondaryForeground": "#ffffff",
//"button.secondaryHoverBackground": "#45494e",
//"charts.blue": "#3794ff",
//"charts.foreground": "#ffffff",
//"charts.green": "#89d185",
//"charts.lines": "#ffffff80",
//"charts.orange": "#d18616",
//"charts.purple": "#b180d7",
//"charts.red": "#ee5500",
//"charts.yellow": "#88bbff",
//"checkbox.background": "#222222",
//"checkbox.border": "#222222",
//"checkbox.foreground": "#888888",
//"debugConsole.errorForeground": "#88bbff",
//"debugConsole.infoForeground": "#3794ff",
//"debugConsole.sourceForeground": "#ffffff",
//"debugConsole.warningForeground": "#88bbff",
//"debugConsoleInputIcon.foreground": "#ffffff",
//"debugIcon.breakpointCurrentStackframeForeground": "#ffcc00",
//"debugIcon.breakpointDisabledForeground": "#848484",
//"debugIcon.breakpointForeground": "#e51400",
//"debugIcon.breakpointStackframeForeground": "#89d185",
//"debugIcon.breakpointUnverifiedForeground": "#848484",
//"debugIcon.continueForeground": "#75beff",
//"debugIcon.disconnectForeground": "#f48771",
//"debugIcon.pauseForeground": "#75beff",
//"debugIcon.restartForeground": "#89d185",
//"debugIcon.startForeground": "#89d185",
//"debugIcon.stepBackForeground": "#75beff",
//"debugIcon.stepIntoForeground": "#75beff",
//"debugIcon.stepOutForeground": "#75beff",
//"debugIcon.stepOverForeground": "#75beff",
//"debugIcon.stopForeground": "#f48771",
//"debugTokenExpression.boolean": "#4e94ce",
//"debugTokenExpression.error": "#f48771",
//"debugTokenExpression.name": "#c586c0",
//"debugTokenExpression.number": "#b5cea8",
//"debugTokenExpression.string": "#ce9178",
//"debugTokenExpression.value": "#cccccc99",
//"debugView.exceptionLabelBackground": "#6c2022",
//"debugView.exceptionLabelForeground": "#ffffff",
//"debugView.stateLabelBackground": "#88888844",
//"debugView.stateLabelForeground": "#ffffff",
//"debugView.valueChangedHighlight": "#569cd6",
//"descriptionForeground": "#ffffffb3",
//"diffEditor.diagonalFill": "#cccccc33",
//"editor.findRangeHighlightBackground": "#3a3d4166",
//"editor.focusedStackFrameHighlightBackground": "#7abd7a4d",
//"editor.foldBackground": "#4444664d",
//"editor.inlineValuesBackground": "#ffc80033",
//"editor.inlineValuesForeground": "#ffffff80",
//"editor.linkedEditingBackground": "#ff00004d",
//"editor.snippetFinalTabstopHighlightBorder": "#525252",
//"editor.snippetTabstopHighlightBackground": "#7c7c7c4d",
//"editor.stackFrameHighlightBackground": "#ffff0033",
//"editor.symbolHighlightBackground": "#444466aa",
//"editorActiveLineNumber.foreground": "#c6c6c6",
//"editorBracketHighlight.foreground1": "#ffd700",
//"editorBracketHighlight.foreground2": "#da70d6",
//"editorBracketHighlight.foreground3": "#179fff",
//"editorBracketHighlight.foreground4": "#00000000",
//"editorBracketHighlight.foreground5": "#00000000",
//"editorBracketHighlight.foreground6": "#00000000",
//"editorBracketHighlight.unexpectedBracket.foreground": "#ff1212cc",
//"editorBracketPairGuide.activeBackground1": "#00000000",
//"editorBracketPairGuide.activeBackground2": "#00000000",
//"editorBracketPairGuide.activeBackground3": "#00000000",
//"editorBracketPairGuide.activeBackground4": "#00000000",
//"editorBracketPairGuide.activeBackground5": "#00000000",
//"editorBracketPairGuide.activeBackground6": "#00000000",
//"editorBracketPairGuide.background1": "#00000000",
//"editorBracketPairGuide.background2": "#00000000",
//"editorBracketPairGuide.background3": "#00000000",
//"editorBracketPairGuide.background4": "#00000000",
//"editorBracketPairGuide.background5": "#00000000",
//"editorBracketPairGuide.background6": "#00000000",
//"editorGhostText.foreground": "#ffffff56",
//"editorGutter.commentRangeForeground": "#c5c5c5",
//"editorGutter.foldingControlForeground": "#c5c5c5",
//"editorHint.foreground": "#eeeeeeb3",
//"editorHoverWidget.foreground": "#ffffff",
//"editorHoverWidget.highlightForeground": "#ffffff",
//"editorHoverWidget.statusBarBackground": "#3d3d3d",
//"editorIndentGuide.activeBackground": "#333333",
//"editorInfo.foreground": "#3794ff",
//"editorInlayHint.background": "#88cc4499",
//"editorInlayHint.foreground": "#222222cc",
//"editorInlayHint.parameterBackground": "#88cc4499",
//"editorInlayHint.parameterForeground": "#222222cc",
//"editorInlayHint.typeBackground": "#88cc4499",
//"editorInlayHint.typeForeground": "#222222cc",
//"editorLightBulb.foreground": "#ffcc00",
//"editorLightBulbAutoFix.foreground": "#75beff",
//"editorLineNumber.activeForeground": "#c6c6c6",
//"editorMarkerNavigationError.headerBackground": "#88bbff1a",
//"editorMarkerNavigationInfo.background": "#3794ff",
//"editorMarkerNavigationInfo.headerBackground": "#3794ff1a",
//"editorMarkerNavigationWarning.headerBackground": "#88bbff1a",
//"editorOverviewRuler.bracketMatchForeground": "#a0a0a0",
//"editorOverviewRuler.commonContentForeground": "#60606066",
//"editorOverviewRuler.unicodeForeground": "#d186167e",
//"editorPane.background": "#222222",
//"editorSuggestWidget.focusHighlightForeground": "#ffffff",
//"editorSuggestWidget.selectedForeground": "#ffffff",
//"editorSuggestWidgetStatus.foreground": "#88888880",
//"editorUnicodeHighlight.border": "#bd9b03",
//"editorUnnecessaryCode.opacity": "#000000aa",
//"editorWidget.foreground": "#ffffff",
//"extensionBadge.remoteBackground": "#88cc44",
//"extensionBadge.remoteForeground": "#222222",
//"extensionIcon.preReleaseForeground": "#1d9271",
//"extensionIcon.starForeground": "#ff8e00",
//"extensionIcon.verifiedForeground": "#3794ff",
//"gitDecoration.addedResourceForeground": "#81b88b",
//"gitDecoration.conflictingResourceForeground": "#e4676b",
//"gitDecoration.deletedResourceForeground": "#c74e39",
//"gitDecoration.ignoredResourceForeground": "#8c8c8c",
//"gitDecoration.renamedResourceForeground": "#73c991",
//"gitDecoration.stageDeletedResourceForeground": "#c74e39",
//"gitDecoration.stageModifiedResourceForeground": "#e2c08d",
//"gitDecoration.submoduleResourceForeground": "#8db9e2",
//"gitlens.closedAutolinkedIssueIconColor": "#a371f7",
//"gitlens.closedPullRequestIconColor": "#f85149",
//"gitlens.decorations.addedForegroundColor": "#81b88b",
//"gitlens.decorations.branchAheadForegroundColor": "#35b15e",
//"gitlens.decorations.branchBehindForegroundColor": "#b15e35",
//"gitlens.decorations.branchDivergedForegroundColor": "#d8af1b",
//"gitlens.decorations.branchMissingUpstreamForegroundColor": "#c74e39",
//"gitlens.decorations.branchUnpublishedForegroundColor": "#35b15e",
//"gitlens.decorations.branchUpToDateForegroundColor": "#888888",
//"gitlens.decorations.copiedForegroundColor": "#73c991",
//"gitlens.decorations.deletedForegroundColor": "#c74e39",
//"gitlens.decorations.ignoredForegroundColor": "#8c8c8c",
//"gitlens.decorations.modifiedForegroundColor": "#cccccc",
//"gitlens.decorations.renamedForegroundColor": "#73c991",
//"gitlens.decorations.untrackedForegroundColor": "#cccccc",
//"gitlens.gutterBackgroundColor": "#ffffff13",
//"gitlens.gutterForegroundColor": "#bebebe",
//"gitlens.gutterUncommittedForegroundColor": "#00bcf299",
//"gitlens.lineHighlightBackgroundColor": "#00bcf233",
//"gitlens.lineHighlightOverviewRulerColor": "#00bcf299",
//"gitlens.mergedPullRequestIconColor": "#a371f7",
//"gitlens.openAutolinkedIssueIconColor": "#3fb950",
//"gitlens.openPullRequestIconColor": "#3fb950",
//"gitlens.trailingLineBackgroundColor": "#00000000",
//"gitlens.trailingLineForegroundColor": "#99999959",
//"gitlens.unpublishedCommitIconColor": "#35b15e",
//"gitlens.unpulledChangesIconColor": "#b15e35",
//"gitlens.unpushlishedChangesIconColor": "#35b15e",
//"icon.foreground": "#c5c5c5",
//"inputOption.activeBackground": "#66666666",
//"inputOption.activeForeground": "#ffffff",
//"inputOption.hoverBackground": "#5a5d5e80",
//"interactive.activeCodeBorder": "#222222",
//"interactive.inactiveCodeBorder": "#000000",
//"keybindingLabel.background": "#8080802b",
//"keybindingLabel.border": "#33333399",
//"keybindingLabel.bottomBorder": "#44444499",
//"keybindingLabel.foreground": "#cccccc",
//"keybindingTable.headerBackground": "#ffffff0a",
//"keybindingTable.rowsBackground": "#ffffff0a",
//"list.deemphasizedForeground": "#8c8c8c",
//"list.errorForeground": "#f88070",
//"list.filterMatchBackground": "#444466aa",
//"list.focusHighlightForeground": "#ffffff",
//"list.focusOutline": "#666666",
//"list.invalidItemForeground": "#b89500",
//"list.warningForeground": "#cca700",
//"listFilterWidget.background": "#653723",
//"listFilterWidget.noMatchesOutline": "#be1100",
//"listFilterWidget.outline": "#00000000",
//"menu.selectionBackground": "#111111",
//"menu.selectionForeground": "#ffffff",
//"menu.separatorBackground": "#bbbbbb",
//"menubar.selectionBackground": "#ffffff1a",
//"menubar.selectionForeground": "#888888",
//"merge.commonContentBackground": "#60606029",
//"merge.commonHeaderBackground": "#60606066",
//"minimap.errorHighlight": "#ff1212b3",
//"minimap.findMatchHighlight": "#d18616",
//"minimap.foregroundOpacity": "#000000",
//"minimap.selectionHighlight": "#264f78",
//"minimap.selectionOccurrenceHighlight": "#676767",
//"minimap.unicodeHighlight": "#d18616",
//"minimap.warningHighlight": "#88bbff",
//"minimapGutter.addedBackground": "#587c0c",
//"minimapGutter.deletedBackground": "#94151b",
//"minimapGutter.modifiedBackground": "#0c7d9d",
//"minimapSlider.activeBackground": "#ffffff09",
//"minimapSlider.background": "#ffffff09",
//"minimapSlider.hoverBackground": "#ffffff09",
//"notebook.cellBorderColor": "#000000",
//"notebook.cellEditorBackground": "#111111",
//"notebook.cellInsertionIndicator": "#666666",
//"notebook.cellStatusBarItemHoverBackground": "#ffffff26",
//"notebook.cellToolbarSeparator": "#80808059",
//"notebook.focusedCellBorder": "#666666",
//"notebook.focusedEditorBorder": "#666666",
//"notebook.inactiveFocusedCellBorder": "#000000",
//"notebook.selectedCellBackground": "#000000",
//"notebook.selectedCellBorder": "#000000",
//"notebook.symbolHighlightBackground": "#ffffff0b",
//"notebookScrollbarSlider.activeBackground": "#ffffff12",
//"notebookScrollbarSlider.background": "#ffffff12",
//"notebookScrollbarSlider.hoverBackground": "#ffffff12",
//"notebookStatusErrorIcon.foreground": "#88bbff",
//"notebookStatusRunningIcon.foreground": "#ffffff",
//"notebookStatusSuccessIcon.foreground": "#89d185",
//"notificationCenterHeader.background": "#424242",
//"notificationLink.foreground": "#3794ff",
//"notifications.background": "#333333",
//"notifications.border": "#424242",
//"notifications.foreground": "#ffffff",
//"notificationsErrorIcon.foreground": "#ee5500",
//"notificationsInfoIcon.foreground": "#3794ff",
//"notificationsWarningIcon.foreground": "#88bbff",
//"panel.dropBorder": "#ffffff",
//"panelSection.border": "#111111",
//"panelSection.dropBackground": "#111111bb",
//"panelSectionHeader.background": "#80808033",
//"ports.iconRunningProcessForeground": "#88cc44",
//"problemsErrorIcon.foreground": "#ee5500",
//"problemsInfoIcon.foreground": "#3794ff",
//"problemsWarningIcon.foreground": "#88bbff",
//"quickInput.background": "#333333",
//"quickInput.foreground": "#ffffff",
//"quickInputList.focusBackground": "#111111",
//"quickInputList.focusForeground": "#ffffff",
//"quickInputTitle.background": "#ffffff1b",
//"sash.hoverBorder": "#666666",
//"scm.providerBorder": "#454545",
//"searchEditor.findMatchBackground": "#44446670",
//"searchEditor.textInputBorder": "#333333",
//"settings.checkboxBackground": "#222222",
//"settings.checkboxBorder": "#222222",
//"settings.checkboxForeground": "#888888",
//"settings.dropdownBackground": "#222222",
//"settings.dropdownBorder": "#222222",
//"settings.dropdownForeground": "#888888",
//"settings.dropdownListBorder": "#333333",
//"settings.focusedRowBackground": "#80808024",
//"settings.focusedRowBorder": "#ffffff1f",
//"settings.headerForeground": "#e7e7e7",
//"settings.modifiedItemIndicator": "#0c7d9d",
//"settings.numberInputBackground": "#333333",
//"settings.numberInputBorder": "#333333",
//"settings.numberInputForeground": "#ffffff",
//"settings.rowHoverBackground": "#80808012",
//"settings.textInputBackground": "#333333",
//"settings.textInputBorder": "#333333",
//"settings.textInputForeground": "#ffffff",
//"sideBar.dropBackground": "#111111bb",
//"sideBySideEditor.horizontalBorder": "#111111",
//"sideBySideEditor.verticalBorder": "#111111",
//"statusBar.debuggingBorder": "#111111",
//"statusBar.noFolderBorder": "#111111",
//"statusBarItem.compactHoverBackground": "#ffffff33",
//"statusBarItem.errorBackground": "#0066eb",
//"statusBarItem.errorForeground": "#ffffff",
//"statusBarItem.prominentForeground": "#666666",
//"statusBarItem.remoteBackground": "#88cc44",
//"statusBarItem.remoteForeground": "#222222",
//"statusBarItem.warningBackground": "#0066eb",
//"statusBarItem.warningForeground": "#ffffff",
//"symbolIcon.arrayForeground": "#ffffff",
//"symbolIcon.booleanForeground": "#ffffff",
//"symbolIcon.classForeground": "#ee9d28",
//"symbolIcon.colorForeground": "#ffffff",
//"symbolIcon.constantForeground": "#ffffff",
//"symbolIcon.constructorForeground": "#b180d7",
//"symbolIcon.enumeratorForeground": "#ee9d28",
//"symbolIcon.enumeratorMemberForeground": "#75beff",
//"symbolIcon.eventForeground": "#ee9d28",
//"symbolIcon.fieldForeground": "#75beff",
//"symbolIcon.fileForeground": "#ffffff",
//"symbolIcon.folderForeground": "#ffffff",
//"symbolIcon.functionForeground": "#b180d7",
//"symbolIcon.interfaceForeground": "#75beff",
//"symbolIcon.keyForeground": "#ffffff",
//"symbolIcon.keywordForeground": "#ffffff",
//"symbolIcon.methodForeground": "#b180d7",
//"symbolIcon.moduleForeground": "#ffffff",
//"symbolIcon.namespaceForeground": "#ffffff",
//"symbolIcon.nullForeground": "#ffffff",
//"symbolIcon.numberForeground": "#ffffff",
//"symbolIcon.objectForeground": "#ffffff",
//"symbolIcon.operatorForeground": "#ffffff",
//"symbolIcon.packageForeground": "#ffffff",
//"symbolIcon.propertyForeground": "#ffffff",
//"symbolIcon.referenceForeground": "#ffffff",
//"symbolIcon.snippetForeground": "#ffffff",
//"symbolIcon.stringForeground": "#ffffff",
//"symbolIcon.structForeground": "#ffffff",
//"symbolIcon.textForeground": "#ffffff",
//"symbolIcon.typeParameterForeground": "#ffffff",
//"symbolIcon.unitForeground": "#ffffff",
//"symbolIcon.variableForeground": "#75beff",
//"tab.activeForeground": "#ffffff",
//"tab.activeModifiedBorder": "#3399cc",
//"tab.inactiveModifiedBorder": "#3399cc80",
//"tab.lastPinnedBorder": "#585858",
//"tab.unfocusedActiveBackground": "#222222",
//"tab.unfocusedActiveModifiedBorder": "#3399cc80",
//"tab.unfocusedInactiveBackground": "#111111",
//"tab.unfocusedInactiveModifiedBorder": "#3399cc40",
//"terminal.border": "#111111",
//"terminal.dropBackground": "#111111bb",
//"terminal.selectionBackground": "#ffffff40",
//"testing.iconErrored": "#f14c4c",
//"testing.iconFailed": "#f14c4c",
//"testing.iconPassed": "#73c991",
//"testing.iconQueued": "#cca700",
//"testing.iconSkipped": "#848484",
//"testing.iconUnset": "#848484",
//"testing.message.error.decorationForeground": "#ee5500",
//"testing.message.error.lineBackground": "#ff000033",
//"testing.message.info.decorationForeground": "#ffffff80",
//"testing.peekBorder": "#ee5500",
//"testing.peekHeaderBackground": "#ee55001a",
//"testing.runAction": "#73c991",
//"textBlockQuote.background": "#7f7f7f1a",
//"textBlockQuote.border": "#007acc80",
//"textCodeBlock.background": "#0a0a0a66",
//"textLink.activeForeground": "#3794ff",
//"textLink.foreground": "#3794ff",
//"textPreformat.foreground": "#d7ba7d",
//"textSeparator.foreground": "#ffffff2e",
//"toolbar.activeBackground": "#63666750",
//"toolbar.hoverBackground": "#5a5d5e50",
//"tree.indentGuidesStroke": "#585858",
//"tree.tableColumnsBorder": "#cccccc20",
//"tree.tableOddRowsBackground": "#ffffff0a",
//"welcomePage.progress.background": "#333333",
//"welcomePage.progress.foreground": "#3794ff",
//"welcomePage.tileBackground": "#333333",
//"welcomePage.tileHoverBackground": "#3d3d3d",
//"welcomePage.tileShadow": "#111111",
//"activityBar.activeBackground": null,
//"activityBar.activeFocusBorder": null,
//"button.border": null,
//"contrastActiveBorder": null,
//"contrastBorder": null,
//"debugToolBar.border": null,
//"diffEditor.border": null,
//"dropdown.listBackground": null,
//"editor.findMatchBorder": null,
//"editor.findMatchHighlightBorder": null,
//"editor.findRangeHighlightBorder": null,
//"editor.rangeHighlightBorder": null,
//"editor.selectionForeground": null,
//"editor.selectionHighlightBorder": null,
//"editor.snippetFinalTabstopHighlightBackground": null,
//"editor.snippetTabstopHighlightBorder": null,
//"editor.symbolHighlightBorder": null,
//"editor.wordHighlightBorder": null,
//"editor.wordHighlightStrongBorder": null,
//"editorCursor.background": null,
//"editorError.background": null,
//"editorError.border": null,
//"editorGhostText.background": null,
//"editorGhostText.border": null,
//"editorGroup.emptyBackground": null,
//"editorGroup.focusedEmptyBorder": null,
//"editorGroupHeader.border": null,
//"editorHint.border": null,
//"editorInfo.background": null,
//"editorInfo.border": null,
//"editorOverviewRuler.background": null,
//"editorSuggestWidget.selectedIconForeground": null,
//"editorUnnecessaryCode.border": null,
//"editorWarning.background": null,
//"editorWidget.resizeBorder": null,
//"inputValidation.errorForeground": null,
//"inputValidation.infoForeground": null,
//"inputValidation.warningForeground": null,
//"list.activeSelectionIconForeground": null,
//"list.filterMatchBorder": null,
//"list.inactiveFocusBackground": null,
//"list.inactiveFocusOutline": null,
//"list.inactiveSelectionIconForeground": null,
//"menu.border": null,
//"menu.selectionBorder": null,
//"menubar.selectionBorder": null,
//"minimap.background": null,
//"notebook.cellHoverBackground": null,
//"notebook.focusedCellBackground": null,
//"notebook.inactiveSelectedCellBorder": null,
//"notebook.outputContainerBackgroundColor": null,
//"notebook.outputContainerBorderColor": null,
//"notificationCenter.border": null,
//"notificationCenterHeader.foreground": null,
//"notificationToast.border": null,
//"panelInput.border": null,
//"panelSectionHeader.border": null,
//"panelSectionHeader.foreground": null,
//"peekViewEditor.matchHighlightBorder": null,
//"quickInput.list.focusBackground": null,
//"quickInputList.focusIconForeground": null,
//"searchEditor.findMatchBorder": null,
//"sideBarSectionHeader.border": null,
//"tab.activeBorder": null,
//"tab.activeBorderTop": null,
//"tab.hoverBackground": null,
//"tab.hoverBorder": null,
//"tab.hoverForeground": null,
//"tab.unfocusedActiveBorderTop": null,
//"tab.unfocusedHoverBackground": null,
//"tab.unfocusedHoverBorder": null,
//"tab.unfocusedHoverForeground": null,
//"terminal.tab.activeBorder": null,
//"terminalCursor.background": null,
//"terminalCursor.foreground": null,
//"testing.message.info.lineBackground": null,
//"titleBar.border": null,
//"toolbar.hoverOutline": null,
//"welcomePage.background": null,
//"window.activeBorder": null,
//"window.inactiveBorder": null
},
"tokenColors": [
{
"scope": [
"variable.language.this"
],
"settings": {
"fontStyle": ""
}
},
{
"scope": "markup.bold",
"settings": {
"fontStyle": "bold"
}
},
{
"scope": [
"invalid",
"markup.italic",
"markup.quote"
],
"settings": {
"fontStyle": "italic"
}
},
{
"scope": "markup.underline",
"settings": {
"fontStyle": "underline"
}
},
{
"scope": [
"source.js.jsx punctuation.section.embedded",
"entity.name.tag",
"string.other.link.description.title",
"support.constant",
"support.variable",
"support.type",
"variable.other.class",
"support.class.builtin.js",
"support.class.console.js",
"meta.property-value",
"variable.parameter.keyframe-list",
"meta.at-rule.keyframes entity.name.function",
"expression.embedded.vue punctuation.definition"
],
"settings": {
"foreground": "#BBA0FF",
"fontStyle": ""
}
},
{
"scope": [
"entity.other.attribute-name.pseudo-class.css",
"entity.name.type.object.console",
"variable.language",
"variable.parameter.function.language.special.self.python",
"storage.type",
"entity.other.attribute-name.pseudo-element.css"
],
"settings": {
"foreground": "#BBA0FF",
"fontStyle": "italic"
}
},
{
"scope": [
"punctuation.definition.string.template"
],
"settings": {
"foreground": "#BBA0FF",
"fontStyle": "bold"
}
},
{
"scope": [
"entity.other.attribute-name.class.css",
"entity.other.attribute-name.parent-selector-suffix.css",
"entity.other.attribute-name.parent-selector-suffix.css punctuation.definition.entity.css",
"meta.definition.function",
"markup.underline.link",
"markup.inserted",
"meta.function-call",
"meta.instance.constructor",
"meta.attribute-with-value.class string",
"string.other.ref",
"string.other.restructuredtext.ref",
"variable.function",
"entity.name.type",
"entity.name.function",
"variable.other.object.property",
"punctuation.separator.key-value",
"meta.definition.function.js",
"support.class.component.js",
"entity.other.inherited-class",
"support.class",
"support.function.misc",
"support.function",
"entity.other.attribute-name.id.css",
"entity.other.attribute-name.id.css punctuation",
"entity.other.attribute-name.class.css punctuation",
"meta.function-call support.function.construct",
"entity.other.attribute-name"
],
"settings": {
"foreground": "#FFDD44"
}
},
{
"scope": "storage.type.function.arrow",
"settings": {
"foreground": "#FFDD44",
"fontStyle": ""
}
},
{
"scope": [
"entity.name.section",
"constant.numeric.line-number.match.find-in-files",
"markup.heading",
"markup.changed",
"meta.attribute-with-value.id string",
"string",
"punctuation.definition.string.begin",
"punctuation.definition.string.end",
"meta.attribute-selector"
],
"settings": {
"foreground": "#88CC44"
}
},
{
"scope": [
"keyword",
"keyword.control",
"constant",
"constant.numeric",
"constant.language",
"constant.other.property",
"constant.character.escape",
"comment keyword.codetag.notation",
"keyword.other.template.begin",
"keyword.other.template.end",
"markup.raw",
"markup.deleted",
"meta.property-list.css variable.other",
"entity.name.constant.preprocessor",
"meta.preprocessor",
"punctuation.section.embedded",
"punctuation.template-string.element.begin",
"punctuation.template-string.element.end",
"string.quoted.template punctuation.definition.string.begin",
"string.quoted.template punctuation.definition.string.end",
"meta.paragraph.markdown meta.dummy.line-break",
"meta.paragraph.markdown meta.hard-line-break.markdown",
"storage",
"storage.class.restructuredtext.ref",
"string.other.link.title",
"string.other.link.description",
"string.regexp punctuation.definition.string.begin",
"string.regexp punctuation.definition.string.end",
"variable.language.arguments",
"storage.modifier",
"keyword.operator.new",
"keyword.operator",
"keyword.operator.spread",
"punctuation.section.embedded.end.php source.php",
"support.function.construct",
"meta.at-rule.keyframes",
"meta.at-rule.keyframes entity.other.attribute-name"
],
"settings": {
"foreground": "#88BBFF"
}
},
{
"scope": [
"variable.other.substitution"
],
"settings": {
"foreground": "#88BBFF",
"fontStyle": "bold"
}
},
{
"scope": [
"meta.function-call meta.function-call.arguments",
"meta.function-call meta.arguments",
"meta.function-call meta.group",
"source.json meta.structure.dictionary",
"meta.object.member",
"punctuation.definition.group",
"string.unquoted.label",
"variable.other.member",
"entity.name.class",
"entity.name.namespace",
"constant.other",
"variable",
"variable.other",
"variable.other.constant.js",
"text.find-in-files",
"source",
"entity.name.type.module",
"source.sql support.function",
"support.other.namespace.php"
],
"settings": {
"foreground": "#FFFFFF",
"fontStyle": ""
}
},
{
"scope": [
"variable.parameter",
"parameters variable.function"
],
"settings": {
"foreground": "#FFFFFF",
"fontStyle": "italic"
}
},
{
"scope": [
"variable.other.property",
"support.variable.property",
"punctuation.separator.key-value",
"meta.object-literal.key",
"variable.other.object.property",
"variable.object.property",
"text.html.basic",
"text.html.vue-html",
"text.html.php",
"text.html.derivative",
"punctuation.definition.variable",
"punctuation.definition.keyword.scss",
"meta.jsx.children.js",
"meta.tag.attributes keyword.operator.assignment",
"support.type.vendored.property-name.css",
"support.type.property-name.json",
"variable.other.constant.property"
],
"settings": {
"foreground": "#BBBBCC"
}
},
{
"scope": "meta.property-name support.type",
"settings": {
"foreground": "#BBBBCC",
"fontStyle": ""
}
},
{
"scope": [
"keyword.other.substitution",
"keyword.operator.heading.restructuredtext",
"keyword.operator.table.row.restructuredtext",
"keyword.operator.table.data.restructuredtext",
"punctuation",
"markup.ignored",
"markup.untracked",
"meta.brace.round",
"meta.brace.square",
"meta.brace.curly",
"meta.delimiter.comma.js",
"meta.function-call.without-arguments.js",
"meta.function-call.method.without-arguments.js",
"source.scss",
"string source punctuation.section.embedded",
"punctuation.definition.tag.begin source",
"source.php"
],
"settings": {
"foreground": "#9999AA"
}
},
{
"scope": [
"comment",
"comment punctuation"
],
"settings": {
"foreground": "#888899",
"fontStyle": "italic"
}
},
{
"scope": "token.info-token",
"settings": {
"foreground": "#6796E6"
}
},
{
"scope": "token.warn-token",
"settings": {
"foreground": "#CD9731"
}
},
{
"scope": "token.error-token",
"settings": {
"foreground": "#F44747"
}
},
{
"scope": "token.debug-token",
"settings": {
"foreground": "#B267E6"
}
}
]
}
File renamed without changes.
File renamed without changes.
-41
View File
@@ -1,41 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Spark Client",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/build/Debug/bin/net6.0-windows/Spark.exe",
"cwd": "${workspaceFolder}/build/Debug/bin/net6.0-windows",
"enableStepFiltering": false,
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": "Spark Test",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/build/Debug/bin/net6.0/sparkcmd.exe",
"args": ["test", "${input:test}"],
"cwd": "${workspaceFolder}/build/Debug/bin/net6.0-windows",
"enableStepFiltering": false,
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": "Attach (.NET Core)",
"type": "coreclr",
"request": "attach"
}
],
"inputs": [
{
"id": "test",
"description": "The test(s) to run",
"type": "promptString"
}
]
}
-37
View File
@@ -1,37 +0,0 @@
{
"cmake.configureOnOpen": false,
"workbench.colorTheme": "Default Dark+",
"C_Cpp.intelliSenseEngine": "Disabled",
"files.associations": {
"*.js": "javascript",
"*.conf": "jsonc",
"array": "cpp",
"xtree": "cpp",
"chrono": "cpp",
"*.ipp": "cpp",
"optional": "cpp",
"regex": "cpp",
"system_error": "cpp",
"format": "cpp",
"future": "cpp",
"istream": "cpp",
"memory": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"variant": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xutility": "cpp",
"xstring": "cpp",
"string": "cpp",
"cstdint": "cpp"
},
"files.exclude": {
"**/.g.cs": true,
"**/.g.i.cs": true
}
}
-44
View File
@@ -1,44 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build Spark Client",
"type": "process",
"command": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Common7\\Tools\\VsDevCmd.bat",
"args": [
"-arch=x64",
"-host_arch=x64",
"&&",
"${workspaceRoot}\\tools\\buildspark.cmd"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"showReuseMessage": false,
"clear": false,
"close": false
}
},
{
"label": "Run Spark Client",
"type": "process",
"command": "${workspaceRoot}\\build\\Debug\\bin\\net6.0-windows\\Spark.exe",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"problemMatcher": []
}
]
}
+2 -2
View File
@@ -1,8 +1,8 @@
cmake_minimum_required(VERSION 3.5)
project(doc)
include(${CMAKE_SOURCE_DIR}/cmake/safe_dep_glob.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/Protobuf.cmake)
include(${CMAKE_SOURCE_DIR}/tools/safe_dep_glob.cmake)
include(${CMAKE_SOURCE_DIR}/tools/Protobuf.cmake)
# DEPENDENCIES
set(DOC_GLOBS
+1 -1
View File
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "6.0.200",
"version": "2.1.508",
"rollForward": "latestMajor"
}
}
-1
View File
@@ -12,7 +12,6 @@ pycodestyle==2.7.0
pycparser==2.20
pylint==2.10.2
PyMeta3==0.5.1
termcolor==1.1.0
toml==0.10.2
wrapt==1.12.1
yapf==0.31.0
+22 -32
View File
@@ -1,10 +1,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32922.545
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
EndProject
@@ -12,17 +12,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\spar
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
ProjectSection(ProjectDependencies) = postProject
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25} = {FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40} = {9FA60215-26AF-3EB7-AB89-D4F4B126EF40}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_websocket", "src\client\spark_websocket\spark_websocket.csproj", "{3201359D-C071-4089-9EDE-B04D759F1508}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api_server", "src\client\spark_api_server\spark_api_server.csproj", "{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -39,14 +37,14 @@ Global
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.Build.0 = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Debug|x64.ActiveCfg = Debug|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Debug|x64.Build.0 = Debug|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Release|x64.ActiveCfg = Release|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.Release|x64.Build.0 = Release|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{FDC3A021-386E-3A2C-A7EB-CBE94A95BE25}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Debug|x64.ActiveCfg = Debug|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Debug|x64.Build.0 = Debug|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Release|x64.ActiveCfg = Release|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.Release|x64.Build.0 = Release|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{9FA60215-26AF-3EB7-AB89-D4F4B126EF40}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.ActiveCfg = Release|x64
@@ -71,6 +69,14 @@ Global
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.Build.0 = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Debug|x64.ActiveCfg = Debug|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Debug|x64.Build.0 = Debug|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Release|x64.ActiveCfg = Release|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.Release|x64.Build.0 = Release|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{A1B7276B-8F81-3D58-A22E-870AF28DF9B9}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.ActiveCfg = Release|x64
@@ -87,22 +93,6 @@ Global
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.Build.0 = Release|x64
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.Build.0 = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.ActiveCfg = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.Build.0 = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.ActiveCfg = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.Build.0 = Debug|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.ActiveCfg = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.Build.0 = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.Build.0 = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.ActiveCfg = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.Build.0 = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.ActiveCfg = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.Build.0 = Debug|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.ActiveCfg = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.Build.0 = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+52 -55
View File
@@ -1,55 +1,52 @@
<Project>
<PropertyGroup>
<ComputerSpecificConfig>..\..\tools\override\$(computername).props</ComputerSpecificConfig>
<SparkRoot>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\..))</SparkRoot>
<SourceRoot>$([System.IO.Path]::GetFullPath($(SparkRoot)\src))</SourceRoot>
<Externals>$(SparkRoot)\externals\windows</Externals>
<DepotName>$([System.IO.Path]::GetFileName($([System.IO.Path]::GetFullPath($(SparkRoot)))))</DepotName>
<ErrorReport>None</ErrorReport>
<Prefer32Bit>False</Prefer32Bit>
<Deterministic>true</Deterministic>
<EnableDefaultContentItems>False</EnableDefaultContentItems>
<ShowMissingItemTypes>false</ShowMissingItemTypes>
<Configuration Condition="'$(configuration)'==''">Debug</Configuration>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
<LangVersion>11</LangVersion>
</PropertyGroup>
<PropertyGroup Label="Output">
<BaseOutputPath>$(SparkRoot)\build\$(Configuration)</BaseOutputPath>
<OutputPath>$(BaseOutputPath)\bin</OutputPath>
<BaseIntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</IntermediateOutputPath>
<ProtoOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</ProtoOutputPath>
<GenDir>$(BaseOutputPath)\gen\$(MSBuildProjectName)</GenDir>
</PropertyGroup>
<Import
Project="$(ComputerSpecificConfig)"
Condition="Exists($(ComputerSpecificConfig))" />
<PropertyGroup Label="ProtoBuf">
<ProtocPluginBase>$(SparkRoot)\src\lib\api\service_compiler</ProtocPluginBase>
<protoc>$(Externals)\bin\protoc.exe</protoc>
<protogen>$(Externals)\bin\protogen.exe</protogen>
</PropertyGroup>
<ItemDefinitionGroup>
<Proto2></Proto2>
<Proto3>
<OutBase>$(IntermediateOutputPath)\gen\%(relativedir)</OutBase>
<OutCS>%(OutBase)%(FileName).cs</OutCS>
<OutCSClient>%(OutBase)%(FileName).client.pb.cs</OutCSClient>
<OutCSServer>%(OutBase)%(FileName).server.pb.cs</OutCSServer>
<OutCSImmutable>%(OutBase)%(FileName).immutable.pb.cs</OutCSImmutable>
<CompileOptions></CompileOptions>
</Proto3>
<Proto3Excel>
<OutBase>$(IntermediateOutputPath)\gen\%(relativedir)</OutBase>
<OutCSExcel>%(OutBase)%(FileName).excel.pb.cs</OutCSExcel>
<CompileOptions></CompileOptions>
</Proto3Excel>
</ItemDefinitionGroup>
</Project>
<Project>
<PropertyGroup>
<ComputerSpecificConfig>..\..\tools\override\$(computername).props</ComputerSpecificConfig>
<SparkRoot>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\..))</SparkRoot>
<SourceRoot>$([System.IO.Path]::GetFullPath($(SparkRoot)\src))</SourceRoot>
<Externals>$(SparkRoot)\externals\windows</Externals>
<DepotName>$([System.IO.Path]::GetFileName($([System.IO.Path]::GetFullPath($(SparkRoot)))))</DepotName>
<ErrorReport>None</ErrorReport>
<Prefer32Bit>False</Prefer32Bit>
<Deterministic>true</Deterministic>
<EnableDefaultContentItems>False</EnableDefaultContentItems>
<ShowMissingItemTypes>false</ShowMissingItemTypes>
<Configuration Condition="'$(configuration)'==''">Debug</Configuration>
</PropertyGroup>
<PropertyGroup Label="Output">
<BaseOutputPath>$(SparkRoot)\build\$(Configuration)</BaseOutputPath>
<OutputPath>$(BaseOutputPath)\bin</OutputPath>
<BaseIntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseOutputPath)\obj\$(MSBuildProjectName)</IntermediateOutputPath>
<GenDir>$(BaseOutputPath)\gen\$(MSBuildProjectName)</GenDir>
</PropertyGroup>
<Import
Project="$(ComputerSpecificConfig)"
Condition="Exists($(ComputerSpecificConfig))" />
<PropertyGroup Label="ProtoBuf">
<ProtocPluginBase>$(SparkRoot)\src\lib\api\service_compiler</ProtocPluginBase>
<protoc>$(Externals)\bin\protoc.exe</protoc>
<protogen>$(Externals)\bin\protogen.exe</protogen>
</PropertyGroup>
<ItemDefinitionGroup>
<Proto2></Proto2>
<Proto3>
<OutBase>$(IntermediateOutputPath)\gen\%(relativedir)</OutBase>
<OutCS>%(OutBase)%(FileName).cs</OutCS>
<OutCSClient>%(OutBase)%(FileName).client.pb.cs</OutCSClient>
<OutCSServer>%(OutBase)%(FileName).server.pb.cs</OutCSServer>
<OutCSImmutable>%(OutBase)%(FileName).immutable.pb.cs</OutCSImmutable>
<CompileOptions></CompileOptions>
</Proto3>
<Proto3Excel>
<OutBase>$(IntermediateOutputPath)\gen\%(relativedir)</OutBase>
<OutCSExcel>%(OutBase)%(FileName).excel.pb.cs</OutCSExcel>
<CompileOptions></CompileOptions>
</Proto3Excel>
</ItemDefinitionGroup>
</Project>
+2 -11
View File
@@ -52,7 +52,8 @@
<Exec Command="set PYTHONPATH=$(SparkRoot)\.venv\Scripts\python" />
<Exec
Command="
$(protoc) %* %(Proto3.FullPath) ^
$(SparkRoot)\tools\build_protos.cmd ^
%(Proto3.FullPath) ^
--error_format=msvs ^
--proto_path=$(SourceRoot) ^
--plugin=&quot;protoc-gen-service=$(ProtocPluginBase)\plugin.cmd&quot; ^
@@ -67,16 +68,6 @@
</ItemGroup>
</Target>
<Target Name="RemoveSystemRuntimeFromRefPack"
BeforeTargets="_HandlePackageFileConflicts"
Condition="'@(Reference -> WithMetadataValue('NugetPackageId', 'System.Runtime.Experimental'))' != ''">
<ItemGroup>
<Reference Remove="@(Reference)"
Condition="$([System.String]::Copy(%(Reference.Identity)).Contains('System.Runtime.dll')) and
'%(Reference.NuGetPackageId)' == 'Microsoft.NETCore.App.Ref'" />
</ItemGroup>
</Target>
<Target
Name="AfterClean"
AfterTargets="Clean">
@@ -1,7 +1,4 @@
#nullable enable
namespace mbts.spark {
using bts.api.analytics;
using mbts.analytics;
using mbts.ui;
using mbts.ui.shell;
@@ -15,9 +12,9 @@ namespace mbts.spark {
readonly AnalyticsExpirationParameters _committed_value;
readonly Property<bool> _is_selected;
readonly Property<ExpirationDriverImmutable?> _driver;
readonly Property<SecurityExpiration?> _deliverable;
readonly Property<SecurityExpiration?> _roll_schedule;
readonly Property<SecurityExpiration> _driver;
readonly Property<SecurityExpiration> _deliverable;
readonly Property<SecurityExpiration> _roll_schedule;
readonly Property<double> _roll_target;
readonly Property<double> _riskless_rate;
readonly Property<double> _settlement_price;
@@ -36,19 +33,18 @@ namespace mbts.spark {
bool _is_last_row_of_month_group;
public AnalyticsExpirationParametersRowVM(
AnalyticsExpirationParametersVM owner, AnalyticsExpirationParameters committed_value) {
this.owner = owner;
_committed_value = committed_value;
public AnalyticsExpirationParametersRowVM(AnalyticsExpirationParametersVM owner, AnalyticsExpirationParameters committed_value) {
this.owner = owner ?? throw new ArgumentNullException(nameof(owner));
_committed_value = committed_value ?? throw new ArgumentNullException(nameof(committed_value));
security = committed_value.security ?? throw new ArgumentException("security must be non-null", nameof(committed_value));
_is_selected = backing(nameof(is_selected), false);
_is_selected.Changed += (oldval, newval) => is_selected_changed?.Invoke(newval);
var is_dirty_srcs = new List<IObservable<bool>>();
(_driver, _is_driver_dirty) = mk_cell_props<ExpirationDriverImmutable?>(nameof(driver), committed_value.driver);
(_deliverable, _is_deliverable_dirty) = mk_cell_props<SecurityExpiration?>(nameof(deliverable), committed_value.deliverable_security);
(_roll_schedule, _is_roll_schedule_dirty) = mk_cell_props<SecurityExpiration?>(nameof(roll_schedule), committed_value.roll_schedule_expiration);
(_driver, _is_driver_dirty) = mk_cell_props(nameof(driver), committed_value.driver_security);
(_deliverable, _is_deliverable_dirty) = mk_cell_props(nameof(deliverable), committed_value.deliverable_security);
(_roll_schedule, _is_roll_schedule_dirty) = mk_cell_props(nameof(roll_schedule), committed_value.roll_schedule_expiration);
(_roll_target, _is_roll_target_dirty) = mk_cell_props(nameof(roll_target), committed_value.roll_target);
(_riskless_rate, _is_riskless_rate_dirty) = mk_cell_props(nameof(riskless_rate), committed_value.riskless_rate);
(_settlement_price, _is_settlement_price_dirty) = mk_cell_props(nameof(settlement_price), committed_value.settlement_price);
@@ -68,22 +64,13 @@ namespace mbts.spark {
}
}
public event Action<bool>? is_selected_changed;
public event Action<bool> is_selected_changed;
public AnalyticsExpirationParametersVM owner { get; }
public SecurityExpiration security { get; }
public ExpirationDriverImmutable? driver {
get => _driver.Value;
set => _driver.set(value);
}
public SecurityExpiration? deliverable {
get => _deliverable.Value;
set => _deliverable.set(value);
}
public SecurityExpiration? roll_schedule {
get => _roll_schedule.Value;
set => _roll_schedule.set(value);
}
public SecurityExpiration driver { get => _driver.Value; set => _driver.set(value); }
public SecurityExpiration deliverable { get => _deliverable.Value; set => _deliverable.set(value); }
public SecurityExpiration roll_schedule { get => _roll_schedule.Value; set => _roll_schedule.set(value); }
public AnalyticsExpirationParameters original_params => _committed_value;
public double roll_target { get => _roll_target.Value; set => _roll_target.set(value); }
@@ -115,15 +102,15 @@ namespace mbts.spark {
public AnalyticsExpirationParameters candidate_value => new(
security,
driver,
deliverable?.is_empty() ?? false ? null : deliverable,
roll_schedule?.is_empty() ?? false ? null : roll_schedule,
deliverable.is_empty() ? null : deliverable,
roll_schedule.is_empty() ? null : roll_schedule,
roll_target,
riskless_rate,
settlement_price,
delta_beta,
vega_beta);
public IObservable<SecurityExpiration?> observe_roll_schedule() =>
public IObservable<SecurityExpiration> observe_roll_schedule() =>
_roll_schedule.observe_current(true);
public IObservable<bool> observe_roll_schedule_dirty() =>
@@ -133,7 +120,7 @@ namespace mbts.spark {
_is_dirty.observe_current(true);
public void revert() {
driver = _committed_value.driver;
driver = _committed_value.driver_security;
deliverable = _committed_value.deliverable_security;
roll_schedule = _committed_value.roll_schedule_expiration;
roll_target = _committed_value.roll_target;
@@ -146,11 +133,11 @@ namespace mbts.spark {
public override string ToString() =>
$"sec: {security}; drv: {driver}; dlv: {deliverable}; roll: {roll_schedule} @ {roll_target}";
public bool Equals(AnalyticsExpirationParametersRowVM? other) =>
public bool Equals(AnalyticsExpirationParametersRowVM other) =>
other is not null &&
security.Equals(other.security);
public override bool Equals(object? obj) =>
public override bool Equals(object obj) =>
Equals(obj as AnalyticsExpirationParametersRowVM);
public override int GetHashCode() =>
@@ -1,8 +1,5 @@
#nullable enable
namespace mbts.spark {
namespace mbts.spark {
using bts.api;
using bts.api.analytics;
using bts.collections;
using bts.reactive;
using bts.utils;
@@ -15,17 +12,11 @@ namespace mbts.spark {
using mbts.ui.utility;
using mbts.utils;
using Spark.Core;
using Spark.Core.Collections;
using Spark.Core.Disposables;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
@@ -35,93 +26,70 @@ namespace mbts.spark {
class AnalyticsExpirationParametersVM : DisposableViewModelBase, IHandleRowSelection {
readonly IBus _bus;
readonly ObservableCollection<AnalyticsExpirationParameters> _parameters = new();
readonly DeferrableAction _sync_visible_rows;
readonly Property<AnalyticsExpirationParametersRowVM?> _copy_row_source;
readonly Property<bool> _auto_copy_rolls_is_checked;
readonly Property<bool> _auto_copy_rates_is_checked;
readonly DeferrableActionWrapper _sync_visible_rows;
readonly Property<AnalyticsExpirationParametersRowVM> _copy_row_source;
readonly DelegateProperty<bool> _is_dirty;
readonly ObservableHashSet<AnalyticsExpirationParametersRowVM> _selected_rows = new();
readonly DeferrableAction _raise_selected_rows_changed;
readonly IRaiseCanExecuteChangedCommand _set_driver_to_nearest_exp_cmd;
IList<string>? _pending_selected_symbols;
readonly HashSet<AnalyticsExpirationParametersRowVM> _selected_rows = new();
AnalyticsExpirationParametersMap? _parameter_map;
AnalyticsExpirationParametersMap _parameter_map;
bool _auto_copy_rolls_is_checked;
bool _auto_copy_rates_is_checked;
(ICommand cmd, IDisposable can_exe_sub)? _smart_copy_roll_target_to_selection_cmd;
(ICommand cmd, IDisposable can_exe_sub)? _smart_copy_riskless_rate_to_selection_cmd;
public AnalyticsExpirationParametersVM(
IBus bus, AnalyticsExpirationParametersSettings startup_data) {
_bus = bus;
_auto_copy_rates_is_checked = backing(nameof(auto_copy_rates_is_checked), false);
_auto_copy_rolls_is_checked = backing(nameof(auto_copy_rolls_is_checked), false);
_raise_selected_rows_changed = new(() => selected_rows_changed?.Invoke(_selected_rows));
public AnalyticsExpirationParametersVM(IBus bus, AnalyticsExpirationParametersSettings startup_data) {
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
var selected_symbol_ref_count = new RefCountMap<string>();
_sync_visible_rows = new(() =>
visible_rows.sync_with(
rows.Where(x => selected_symbol_ref_count.ContainsKey(x.security.symbol))));
visible_rows.sync_with(rows.Where(x => selected_symbol_ref_count.ContainsKey(x.security.symbol))));
non_options_with_empty = new ObservableAggregateCollection<SecurityExpiration>(
new() { SecurityExpiration.empty }, non_options);
_copy_row_source = backing<AnalyticsExpirationParametersRowVM?>(nameof(copy_row_source));
_copy_row_source = backing<AnalyticsExpirationParametersRowVM>(nameof(copy_row_source));
_is_dirty = backing(nameof(is_dirty), () => rows.Any(r => r.is_dirty));
if (startup_data is not null) {
_pending_selected_symbols = startup_data.selected_symbols;
if (!startup_data.selected_symbols.is_null_or_empty()) {
selected_symbols.AddRange(startup_data.selected_symbols);
}
auto_copy_rolls_is_checked = startup_data.auto_copy_rolls_is_checked;
auto_copy_rates_is_checked = startup_data.auto_copy_rates_is_checked;
}
var explicit_drivers = new ObservableCollection<ExpirationDriverImmutable>();
drivers = ObservableAggregateCollection.create(
new() { new ExpirationDriverImmutable(new() { TimeWeightedInterpolated = new() }) },
explicit_drivers);
_set_driver_to_nearest_exp_cmd = new Command(
() => _set_driver_to_nearest_exp(_selected_rows), () => _selected_rows.Count > 0);
commit_cmd = ObservantCommand.create(_commit, out var can_commit_observer);
revert_cmd = ObservantCommand.create(_revert, out var can_revert_observer);
selected_rows_changed += _ => _set_driver_to_nearest_exp_cmd.RaiseCanExecuteChanged();
_dispose = Disposable.Create(
_selected_rows.Subscribe((s, e) => _raise_selected_rows_changed.Invoke()),
ObservableAutoWrapper.connect(_parameters, rows, p => new(this, p), r => r.Dispose()),
ObservableAutoWrapper.connect(
non_options,
explicit_drivers,
sec => new ExpirationDriverImmutable(new() { Security = sec.to_api_sec_exp() })),
rows.Subscribe((s, e) => _sync_visible_rows.Invoke()),
rows.Subscribe((s, e) => _sync_visible_rows.execute()),
_bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(
CompositeObserver.create(
Observer.Create<AnalyticsExpirationParametersMap>(_on_parameter_map),
can_commit_observer.wrap<bool, AnalyticsExpirationParametersMap>(m => m is not null))),
ObservableAutoWrapper.connect_item_hooks(selected_symbols, sym => {
if (selected_symbol_ref_count.increment_adds_key(sym)) {
_sync_visible_rows.Invoke();
_sync_visible_rows.execute();
}
return Disposable.Create(() => {
if (selected_symbol_ref_count.decrement_removes_key(sym)) {
_sync_visible_rows.Invoke();
_sync_visible_rows.execute();
}
});
}),
ObservableAutoWrapper.connect_item_hooks(
rows, r => r.observe_is_dirty().Subscribe(_ => _is_dirty.refresh())),
ObservableAutoWrapper.connect_item_hooks(rows, r => r.observe_is_dirty().Subscribe(_ => _is_dirty.refresh())),
_is_dirty.observe_current(true).OnDispatcher().Subscribe(can_revert_observer),
Disposable.wrap_collection(rows),
Disposable.Create(() => {
rows.DisposeAll();
_smart_copy_roll_target_to_selection_cmd?.can_exe_sub?.Dispose();
_smart_copy_riskless_rate_to_selection_cmd?.can_exe_sub?.Dispose();
}));
}
public event Action<IReadOnlySet<AnalyticsExpirationParametersRowVM>>? selected_rows_changed;
public ObservableCollection<SecurityExpiration> non_options { get; } = new();
public IReadOnlyObservableCollection<ExpirationDriverImmutable> drivers { get; }
public ObservableCollection<SecurityExpiration> non_options_with_empty { get; } = new();
public ObservableCollection<AnalyticsExpirationParametersRowVM> rows { get; } = new();
public ObservableCollection<AnalyticsExpirationParametersRowVM> visible_rows { get; } = new();
public AnalyticsExpirationParametersRowVM? copy_row_source {
public AnalyticsExpirationParametersRowVM copy_row_source {
get => _copy_row_source.Value;
set => _copy_row_source.set(value);
}
@@ -132,29 +100,18 @@ namespace mbts.spark {
public bool is_dirty => _is_dirty.Value;
public bool auto_copy_rolls_is_checked {
get => _auto_copy_rolls_is_checked.Value;
set => _auto_copy_rolls_is_checked.set(value);
get => _auto_copy_rolls_is_checked;
set => Set(ref _auto_copy_rolls_is_checked, value);
}
public IObservable<bool> observe_auto_copy_rolls() =>
_auto_copy_rolls_is_checked.observe_current(true);
public bool auto_copy_rates_is_checked {
get => _auto_copy_rates_is_checked.Value;
set => _auto_copy_rates_is_checked.set(value);
get => _auto_copy_rates_is_checked;
set => Set(ref _auto_copy_rates_is_checked, value);
}
public IObservable<bool> observe_auto_copy_rates() =>
_auto_copy_rates_is_checked.observe_current(true);
public ICommand toggle_auto_copy_rates_cmd =>
new Command(() => auto_copy_rates_is_checked = !auto_copy_rates_is_checked);
public ICommand toggle_auto_copy_rolls_cmd =>
new Command(() => auto_copy_rolls_is_checked = !auto_copy_rolls_is_checked);
public ICommand commit_cmd { get; }
public ICommand revert_cmd { get; }
public ICommand set_driver_to_nearest_exp_cmd => _set_driver_to_nearest_exp_cmd;
public ICommand copy_driver_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.driver = f.driver);
public ICommand copy_deliverable_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.deliverable = f.deliverable);
public ICommand copy_roll_schedule_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.roll_schedule = f.roll_schedule);
@@ -181,7 +138,7 @@ namespace mbts.spark {
public IEnumerable<SecurityExpiration> get_smart_copy_roll_exps(
SecurityExpiration roll_schedule_expiration) {
foreach (var (exp, exp_params) in (_parameter_map?.exp_map).empty_if_null()) {
foreach (var (exp, exp_params) in _parameter_map?.exp_map.empty_if_null()) {
if (exp_params.roll_schedule_expiration.Equals(roll_schedule_expiration)) {
yield return exp;
}
@@ -195,38 +152,17 @@ namespace mbts.spark {
auto_copy_rolls_is_checked = auto_copy_rolls_is_checked
};
void _set_driver_to_nearest_exp(IEnumerable<AnalyticsExpirationParametersRowVM> rows) {
Func<ExpirationDriverImmutable, bool> is_unexpired = (d) => {
var st = d.Security.to_sec_exp().security_tuple.to_api_sec_tuple();
var exp = d.Security.Expiration.date_time();
return SecurityExpirationHelper.is_unexpired(st, exp);
};
foreach (var r in rows) {
if (drivers
.Where(d => d.HasSecurity && d.Security.Symbol == r.security.symbol)
.Where(d => is_unexpired(d))
.TryGetMinElement(
d => (r.security.expiration - d.Security.Expiration.date_time()).Ticks.abs(),
out var nearest_exp)) {
r.driver = nearest_exp;
}
}
}
Action<AnalyticsExpirationParametersRowVM> _copy_to_selection(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
Action<AnalyticsExpirationParametersRowVM> _copy_to_selection(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
from_row => {
foreach (var to_row in _selected_rows) {
copy_to_row(from_row, to_row);
}
};
ICommand _copy_to_selection_cmd(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
ICommand _copy_to_selection_cmd(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
Command.create(_copy_to_selection(copy_to_row));
Action<AnalyticsExpirationParametersRowVM> _smart_copy_to_selection(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
Action<AnalyticsExpirationParametersRowVM> _smart_copy_to_selection(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
from_row => {
foreach (var to_row in _get_smart_copy_roll_target_rows(from_row)) {
copy_to_row(from_row, to_row);
@@ -235,26 +171,21 @@ namespace mbts.spark {
(ICommand cmd, IDisposable can_exe_sub) _smart_copy_to_selection_cmd(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) {
var copy_fn = _smart_copy_to_selection(copy_to_row);
var cmd = ObservantCommand.create<AnalyticsExpirationParametersRowVM?>(
r => copy_fn(r ?? throw new InvalidOperationException()),
observe_can_execute,
out var can_exe_observer);
var can_exe_sub = _copy_row_source.observe_current(true).OnDispatcher()
.Subscribe(can_exe_observer);
var cmd = ObservantCommand.create(
_smart_copy_to_selection(copy_to_row), observe_can_execute, out var can_exe_observer);
var can_exe_sub = _copy_row_source.observe_current(true).OnDispatcher().Subscribe(can_exe_observer);
return (cmd, can_exe_sub);
static IObservable<bool> observe_can_execute(AnalyticsExpirationParametersRowVM? row) =>
static IObservable<bool> observe_can_execute(AnalyticsExpirationParametersRowVM row) =>
row is null ?
Observable.Return(false) :
row.observe_roll_schedule()
.CombineLatest(row.observe_roll_schedule_dirty(), (rs, rs_dirty) => (rs, rs_dirty))
.Select(tup => !tup.rs?.is_empty() ?? false && !tup.rs_dirty)
.Select(tup => !tup.rs.is_empty() && !tup.rs_dirty)
.OnDispatcher();
}
IEnumerable<AnalyticsExpirationParametersRowVM> _get_smart_copy_roll_target_rows(
AnalyticsExpirationParametersRowVM row) {
IEnumerable<AnalyticsExpirationParametersRowVM> _get_smart_copy_roll_target_rows(AnalyticsExpirationParametersRowVM row) {
var target_exps = get_smart_copy_roll_exps(
row.original_params.roll_schedule_expiration)
.ToHashSet();
@@ -276,13 +207,11 @@ namespace mbts.spark {
}
}
[MemberNotNull(nameof(_parameter_map))]
void _on_parameter_map(AnalyticsExpirationParametersMap parameter_map) {
bool is_first_update = _parameter_map is null;
_parameter_map = parameter_map;
_parameter_map = parameter_map ?? throw new ArgumentNullException(nameof(parameter_map));
_parameters.sync_with(parameter_map.get_sorted_exps().Select(parameter_map.get_parameter));
non_options.sync_with(
parameter_map.get_sorted_exps().Where(exp => exp.security_type != SecurityType.Option));
non_options.sync_with(parameter_map.get_sorted_exps().Where(exp => exp.security_type != SecurityType.Option));
// Set `is_last_row_of_month_group` for each row
foreach (var exp_rows in rows.GroupBy(r => r.security.expiration.Month)) {
@@ -294,10 +223,10 @@ namespace mbts.spark {
}
symbols.sync_with(_parameters.Select(p => p.security.symbol).Distinct().Ordered());
using var _ = _sync_visible_rows.defer();
using var _ = _sync_visible_rows.defer_execution();
if (is_first_update) {
selected_symbols.sync_with(_pending_selected_symbols?.Intersect(symbols) ?? symbols);
_pending_selected_symbols = null;
// select all symbols on first update
selected_symbols.sync_with(symbols);
}
}
@@ -9,36 +9,18 @@
xmlns:u="clr-namespace:mbts.ui"
xmlns:cv="clr-namespace:mbts.ui.converters"
xmlns:shell="clr-namespace:mbts.ui.shell"
Background="{u:BTSBrush UI.common_background}">
Background="{StaticResource CommonBackground}">
<UserControl.Resources>
<cv:DoubleTextConverter x:Key="DoubleTextConverter" />
<cv:DoubleTextConverter
x:Key="RisklessRateConverter"
Multiplier="100" />
<CollectionViewSource x:Key="Drivers" Source="{Binding drivers}" />
<CollectionViewSource x:Key="NonOptionsWithEmpty" Source="{Binding non_options_with_empty}" />
<DataTemplate x:Key="DriverTemplate">
<TextBlock Text="{Binding Converter={x:Static shell:AnalyticsExpirationParametersView.driver_display_text_converter}}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger
Property="Text"
Value="None">
<Setter
Property="FontStyle"
Value="Italic" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
<shell:ExpTextConverter
x:Key="ExpirationTextConverter"
ShowSymbol="True"
MapExp="True" />
<DataTemplate x:Key="ExpirationTemplate">
<TextBlock Text="{Binding Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_text_converter}}">
<TextBlock Text="{Binding Converter={StaticResource ExpirationTextConverter}}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
@@ -48,6 +30,9 @@
<Setter
Property="FontStyle"
Value="Italic" />
<Setter
Property="Foreground"
Value="Gray" />
</Trigger>
</Style.Triggers>
</Style>
@@ -117,20 +102,6 @@
CommandParameter="{Binding}"
/>
</ContextMenu>
<Style x:Key="TextBlockCellElement" TargetType="TextBlock">
<Setter
Property="Foreground"
Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=DataGridCell}}" />
</Style>
<Style x:Key="ComboBoxCellElement" TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
<Setter
Property="Foreground"
Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=DataGridCell}}" />
<Setter Property="Margin" Value="2" />
<Setter Property="IsSynchronizedWithCurrentItem" Value="False" />
</Style>
</UserControl.Resources>
<Grid>
<Grid.Resources>
@@ -153,23 +124,17 @@
SelectedItems="{Binding selected_symbols}"
HorizontalAlignment="Left"
Margin="5,2,2,2"
TextBlock.Foreground="Black"
HeaderContent="Symbols"
ShowSelectAll="True">
<c:ComboCheckBox.HeaderContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="{u:BTSColor UI.default_text}" />
</DataTemplate>
</c:ComboCheckBox.HeaderContentTemplate>
</c:ComboCheckBox>
ShowSelectAll="True"
/>
<WrapPanel>
<TextBlock
Margin="5,5,0,0" Foreground="{u:BTSBrush UI.default_text}" Text="Auto copy rolls:" />
<TextBlock Margin="5,5,0,0" Text="Auto copy rolls:" />
<CheckBox Margin="5,5,10,0" IsChecked="{Binding auto_copy_rolls_is_checked}" />
</WrapPanel>
<WrapPanel>
<TextBlock
Margin='0,5,0,0' Foreground="{u:BTSBrush UI.default_text}" Text="Auto copy rates:" />
<TextBlock Margin='0,5,0,0' Text="Auto copy rates:" />
<CheckBox Margin="5,5,0,0" IsChecked="{Binding auto_copy_rates_is_checked}" />
</WrapPanel>
</StackPanel>
@@ -177,8 +142,8 @@
x:Name="_grid"
Grid.Row="1"
ItemsSource="{Binding visible_rows}"
Background="Transparent"
VerticalGridLinesBrush="{u:BTSColor Grid.grid_line}"
AlternatingRowBackground="{u:BTSColor MarketData.driver_background}"
VerticalGridLinesBrush="Gray"
EnableRowVirtualization="True"
EnableColumnVirtualization="True"
CanUserAddRows="False"
@@ -191,10 +156,35 @@
SelectionUnit="FullRow"
SelectedUnits="{Binding selected_rows}"
PreviewMouseRightButtonUp="_grid_PreviewMouseRightButtonUp">
<c:DataGridEx.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="IsSelected" Value="{Binding is_selected, Mode=TwoWay}"/>
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="BorderThickness" Value="1" />
<Style.Triggers>
<Trigger
Property="IsSelected"
Value="True">
<Setter
Property="Background"
Value="{u:BTSColor Grid.grid_selection_background}" />
<Setter
Property="BorderBrush"
Value="{u:BTSColor Grid.grid_selection_background}" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="IsSelected" Value="{Binding is_selected, Mode=TwoWay}"/>
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger
Property="IsSelected"
Value="true">
<Setter
Property="Background"
Value="{u:BTSColor Grid.grid_selection_background}" />
</Trigger>
<DataTrigger
Binding="{Binding is_last_row_of_month_group}"
Value="True">
@@ -207,7 +197,7 @@
</DataTrigger>
</Style.Triggers>
</Style>
</c:DataGridEx.RowStyle>
</DataGrid.RowStyle>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter
@@ -219,6 +209,9 @@
<Setter
Property="HorizontalContentAlignment"
Value="Center" />
<Setter
Property="BorderThickness"
Value="0,0,1,0" />
<Setter
Property="BorderBrush"
Value="Black" />
@@ -233,7 +226,7 @@
<DataGrid.Columns>
<DataGridTextColumn
Header="Security"
Binding="{Binding security, Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_text_converter}}"
Binding="{Binding security, Converter={StaticResource ExpirationTextConverter}}"
IsReadOnly="True">
<DataGridTextColumn.CellStyle>
<Style
@@ -245,6 +238,9 @@
<Setter
Property="Foreground"
Value="{u:BTSColor Name=header_text}" />
<Setter
Property="BorderThickness"
Value="0" />
<Setter
Property="VerticalContentAlignment"
Value="Center" />
@@ -291,7 +287,9 @@
<DataTrigger
Binding="{Binding is_driver_dirty}"
Value="True">
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
<Setter
Property="BorderBrush"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -299,10 +297,10 @@
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding Source={StaticResource Drivers}}"
ItemTemplate="{StaticResource DriverTemplate}"
ItemsSource="{Binding DataContext.non_options, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
ItemTemplate="{StaticResource ExpirationTemplate}"
SelectedItem="{Binding driver, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource ComboBoxCellElement}" />
Margin="2" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
@@ -320,28 +318,20 @@
<DataTrigger
Binding="{Binding is_deliverable_dirty}"
Value="True">
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
<Setter
Property="BorderBrush"
Value="Red" />
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding is_deliverable_dirty}" Value="False" />
<Condition Binding="{Binding
deliverable,
Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_is_defined_converter}}"
Value="False" />
</MultiDataTrigger.Conditions>
<Setter Property="Foreground" Value="{u:BTSColor UI.default_foreground_dark}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding Source={StaticResource NonOptionsWithEmpty}}"
ItemsSource="{Binding DataContext.non_options_with_empty, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
ItemTemplate="{StaticResource ExpirationTemplate}"
SelectedItem="{Binding deliverable, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource ComboBoxCellElement}" />
Margin="2" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
@@ -359,28 +349,20 @@
<DataTrigger
Binding="{Binding is_roll_schedule_dirty}"
Value="True">
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
<Setter
Property="BorderBrush"
Value="Red" />
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding is_roll_schedule_dirty}" Value="False" />
<Condition Binding="{Binding
roll_schedule,
Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_is_defined_converter}}"
Value="False" />
</MultiDataTrigger.Conditions>
<Setter Property="Foreground" Value="{u:BTSColor UI.default_foreground_dark}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding Source={StaticResource NonOptionsWithEmpty}}"
ItemsSource="{Binding DataContext.non_options_with_empty, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
ItemTemplate="{StaticResource ExpirationTemplate}"
SelectedItem="{Binding roll_schedule, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource ComboBoxCellElement}" />
Margin="2" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
@@ -396,7 +378,9 @@
<DataTrigger
Binding="{Binding is_roll_target_dirty}"
Value="True">
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
<Setter
Property="BorderBrush"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -407,15 +391,14 @@
Text="{Binding roll_target, Converter={StaticResource DoubleTextConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource RollTargetContextMenu}"
Style="{StaticResource TextBlockCellElement}" />
ContextMenu="{StaticResource RollTargetContextMenu}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox
Text="{Binding roll_target, Converter={StaticResource DoubleTextConverter}}"
Margin="2" />
Text="{Binding roll_target, Converter={StaticResource DoubleTextConverter}}"
Margin="2" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -431,7 +414,9 @@
<DataTrigger
Binding="{Binding is_riskless_rate_dirty}"
Value="True">
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
<Setter
Property="BorderBrush"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -442,14 +427,12 @@
Text="{Binding riskless_rate, Converter={StaticResource RisklessRateConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource RisklessRateContextMenu}"
Style="{StaticResource TextBlockCellElement}" />
ContextMenu="{StaticResource RisklessRateContextMenu}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox
Text="{Binding riskless_rate, Converter={StaticResource RisklessRateConverter}}" />
<TextBox Text="{Binding riskless_rate, Converter={StaticResource RisklessRateConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -465,7 +448,9 @@
<DataTrigger
Binding="{Binding is_settlement_price_dirty}"
Value="True">
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
<Setter
Property="BorderBrush"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -476,14 +461,12 @@
Text="{Binding settlement_price, Converter={StaticResource DoubleTextConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource SettlementPriceContextMenu}"
Style="{StaticResource TextBlockCellElement}" />
ContextMenu="{StaticResource SettlementPriceContextMenu}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox
Text="{Binding settlement_price, Converter={StaticResource DoubleTextConverter}}" />
<TextBox Text="{Binding settlement_price, Converter={StaticResource DoubleTextConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -500,7 +483,9 @@
<DataTrigger
Binding="{Binding is_delta_beta_dirty}"
Value="True">
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
<Setter
Property="BorderBrush"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -511,14 +496,12 @@
Text="{Binding delta_beta, Converter={StaticResource DoubleTextConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource DeltaBetaContextMenu}"
Style="{StaticResource TextBlockCellElement}" />
ContextMenu="{StaticResource DeltaBetaContextMenu}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox
Text="{Binding delta_beta, Converter={StaticResource DoubleTextConverter}}" />
<TextBox Text="{Binding delta_beta, Converter={StaticResource DoubleTextConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
@@ -535,7 +518,9 @@
<DataTrigger
Binding="{Binding is_vega_beta_dirty}"
Value="True">
<Setter Property="Foreground" Value="{u:BTSColor UI.input_dirty_foreground}" />
<Setter
Property="BorderBrush"
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -543,11 +528,10 @@
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock
Text="{Binding vega_beta, Converter={StaticResource DoubleTextConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource VegaBetaContextMenu}"
Style="{StaticResource TextBlockCellElement}" />
Text="{Binding vega_beta, Converter={StaticResource DoubleTextConverter}}"
VerticalAlignment="Center"
Margin="2,0,2,0"
ContextMenu="{StaticResource VegaBetaContextMenu}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
@@ -1,14 +1,10 @@
#nullable enable
namespace mbts.ui.shell {
using bts.api.analytics;
namespace mbts.ui.shell {
using bts.api;
using mbts.spark;
using mbts.ui.controls;
using mbts.ui.converters;
using mbts.ui.extensions;
using Spark.Core.Disposables;
using System;
using System.Windows;
using System.Windows.Controls;
@@ -20,8 +16,8 @@ namespace mbts.ui.shell {
/// Interaction logic for AnalyticsExpirationParametersView.xaml
/// </summary>
partial class AnalyticsExpirationParametersView : UserControl {
IDisposable? _context_menu_op;
IDisposable? _data_context_hooks;
IDisposable _context_menu_op;
IDisposable _data_context_hooks;
public AnalyticsExpirationParametersView() {
InitializeComponent();
@@ -35,28 +31,6 @@ namespace mbts.ui.shell {
}
}
public static ExpirationTextConverter expiration_text_converter =>
new() {
ShowSymbol = true,
ShowType = true,
MapExp = true
};
public static IValueConverter driver_display_text_converter =>
ValueConverter.create<ExpirationDriverImmutable?, string?>(
d => d.HasValue ?
d.Value.ModeCase switch {
ExpirationDriver.ModeOneofCase.Security =>
expiration_text_converter.convert(d.Value.Security.to_sec_exp()),
ExpirationDriver.ModeOneofCase.TimeWeightedInterpolated => "Calculate",
_ => null
} :
null);
public static IValueConverter expiration_is_defined_converter =>
ValueConverter.create<SecurityExpiration?, bool>(exp =>
exp is not null && exp.expiration != default);
void _grid_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e) {
Disposable.dispose(ref _context_menu_op);
if (e.OriginalSource is not FrameworkElement el || DataContext is not AnalyticsExpirationParametersVM vm) {
@@ -73,4 +47,30 @@ namespace mbts.ui.shell {
e.Handled = true;
}
}
class ExpTextConverter : IValueConverter {
public ExpTextConverter() {
NullOrEmptyText = "None";
}
public bool ShowType { get; set; }
public bool ShowSymbol { get; set; }
public bool MapExp { get; set; }
public string NullOrEmptyText { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
var exp = value as SecurityExpiration;
if (exp == null || exp.is_empty()) {
return NullOrEmptyText;
}
return ShowSymbol ?
SecurityFormatter.format_future(exp.symbol, exp.expiration) :
DateFormatter.Format(exp.expiration, DateFormat.MonthCodeLastDigitYear);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
}
@@ -1,13 +1,10 @@
namespace mbts.spark {
namespace mbts.spark {
using bts.api;
using bts.spark;
using mbts.ui;
using mbts.ui.shell;
using Spark.Core.Disposables;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
@@ -41,30 +38,11 @@ namespace mbts.spark {
public void thread_init() {
_vm = new AnalyticsExpirationParametersVM(_bus, _init_settings);
var auto_copy_rolls_cmd = new SparkCommandCommand(
"Auto Copy Rolls", null, _vm.toggle_auto_copy_rolls_cmd);
_vm.SubscribeDisposed(_vm.observe_auto_copy_rolls().Subscribe(v =>
auto_copy_rolls_cmd.icon = v ? Icons.RecurringSchedule : Icons.RecurringScheduleGray));
var auto_copy_rates_cmd = new SparkCommandCommand(
"Auto Copy Rates", null, _vm.toggle_auto_copy_rates_cmd);
_vm.SubscribeDisposed(_vm.observe_auto_copy_rates().Subscribe(v =>
auto_copy_rates_cmd.icon = v ? Icons.FinancialGrowth : Icons.FinancialGrowthGray));
_view = new AnalyticsExpirationParametersView { DataContext = _vm };
_commands = new() {
new SparkCommandCommand("Commit", Icons.Disk, _vm.commit_cmd, new KeyGesture(Key.S, ModifierKeys.Control)),
new SparkCommandCommand("Revert", Icons.UndoCircular, _vm.revert_cmd, new KeyGesture(Key.Z, ModifierKeys.Control)),
auto_copy_rates_cmd,
auto_copy_rolls_cmd,
new SparkCommandCommand(
"Set Driver to Nearest Exp", null, _vm.set_driver_to_nearest_exp_cmd) {
show_in_toolbar = false,
show_in_context_menu = true
},
};
_view = new AnalyticsExpirationParametersView { DataContext = _vm };
}
}
}
@@ -1,69 +1,101 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using bts;
using mbts.analytics;
using bts.api.analytics;
using System.Reactive.Linq;
using bts.api;
using System.Threading;
namespace mbts.spark {
using bts;
using bts.api;
using bts.api.analytics;
// 1. Reads exp params from the network and publishes
// it to the BB
// 2. Listens to ExpirationParametersCommitTag and
// writes the calls into persistence to save the data
public class AnalyticsParametersManager : IDisposable {
private readonly ThreadedBlackboard _bb;
private AnalyticsService _analytics_service;
private List<IDisposable> _disposables = new List<IDisposable>();
private IDictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>
_data = new Dictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>();
private readonly ITag<IEnumerable<AnalyticsExpirationParameters>>
_in_bb_exp_params_commit_tag = SparkTags.ExpirationParametersCommitTag;
private readonly ITag<SystemContractData> _in_contracts_tag = SparkTags.SystemContractsTag;
private readonly ITag<AnalyticsExpirationParametersMap> _out_exp_params_tag =
SparkTags.ExpirationParametersInputTag;
private HighPerformanceTimer _timer = new HighPerformanceTimer();
using mbts.analytics;
public AnalyticsParametersManager(ThreadedBlackboard bb,
AnalyticsService analytics_server) {
_bb = bb;
_analytics_service = analytics_server;
var exp_params_sub = _analytics_service.subscribei_exp_parameters()
.ObserveOn(SynchronizationContext.Current)
.Subscribe(_on_exp_parameters);
_disposables.Add(exp_params_sub);
_bb.subscribe(_in_bb_exp_params_commit_tag);
_bb.subscribe(_in_contracts_tag);
_bb.data_callback += _on_bb_data;
}
using Spark.Core.Disposables;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
/// <summary>
/// Reads exp params from the network and publishes it to the bus; listens to
/// <see cref="SparkTags.ExpirationParametersCommitTag"/> and persists the data
/// </summary>
public sealed class AnalyticsParametersManager : IDisposable {
IDisposable? _dispose;
public AnalyticsParametersManager(IBus bus, AnalyticsService analytics_service) {
var contracts_src = bus.subscribe(SparkTags.SystemContractsTag);
var exp_params_in_src = analytics_service.subscribei_exp_parameters()
.Select(upd => upd.all
.SelectMany(ep => ep.ParamList
.Select(ep => new AnalyticsExpirationParameters(ep)))
.ToDictionary(ep => ep.security));
var exp_params_out_src = bus.subscribe(SparkTags.ExpirationParametersCommitTag)
.Select(eps => eps
.Where(ep => ep.security.expiration.Date >= DateTime.Today - TimeSpan.FromDays(1)));
_dispose = Disposable.Create(
exp_params_in_src.CombineLatest(contracts_src)
.Select(tup => new AnalyticsExpirationParametersMap(tup.First, tup.Second))
.ObserveOn(SynchronizationContext.Current ?? throw new InvalidOperationException())
.Subscribe(bus.post_callback(SparkTags.ExpirationParametersInputTag)),
exp_params_out_src.Subscribe(save_exp_params));
void save_exp_params(IEnumerable<AnalyticsExpirationParameters> exp_params) {
Func<AnalyticsExpirationParameters, bool> is_unexpired = (p) => {
var st = p.driver_security.security_tuple.to_api_sec_tuple();
var exp = p.security.expiration;
return SecurityExpirationHelper.is_unexpired(st, exp);
};
exp_params = exp_params.Where(t => is_unexpired(t));
private void _on_bb_data(object tag, object data) {
if (_in_contracts_tag.Equals(tag)) {
_assemble_and_publish();
} else if (_in_bb_exp_params_commit_tag == tag) {
// listens to the commit tag and saves it
Log.Gen.info($"AnalyticsParametersManager received commit req. count:{exp_params.Count()}");
var to_save = new ExpirationParameterEntryList();
IEnumerable<AnalyticsExpirationParameters> exp_params =
data as IEnumerable<AnalyticsExpirationParameters>;
exp_params = exp_params.Where(e => e.security.expiration.Date >=
DateTime.Now.Date.Subtract(TimeSpan.FromDays(1)));
bts.Log.Gen.info(
String.Format("AnalyticsParametersManager._on_bb_data received commit count:{0}",
exp_params.Count()));
ExpirationParameterEntryList to_save = new ExpirationParameterEntryList();
to_save.ParamList.AddRange(exp_params.Select(i => i.to_exp_param_entry()));
Log.Gen.record(
null,
(dt, elapsed, res) => {
var msg = "AnalyticsParametersManager saved exp_params. " +
$"count:{exp_params.Count()} t:{elapsed.TotalMilliseconds:0.000}ms";
return (LogLevel.Info, msg);
},
() => analytics_service.set_exp_parameters(to_save));
_timer.start();
_analytics_service.set_exp_parameters(to_save);
_timer.stop();
bts.Log.Gen.info(
String.Format("AnalyticsParametersManager saved exp_params count:{0} t:{1} msecs",
exp_params.Count(), _timer.lastIntervalTime));
}
}
public void Dispose() =>
Disposable.dispose(ref _dispose);
void _on_exp_parameters(bts.api.core.Update<ExpirationParameterEntryListImmutable, int> update) {
_data = new Dictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>();
bts.Log.Gen.info(String.Format("AnalyticsParametersManager._on_exp_parameters received count:{0}",
update.all.Count()));
bts.Log.assert(update.all.Count() == 0 || update.all.Count() == 1);
foreach (ExpirationParameterEntryListImmutable l in update.all) {
foreach (ExpirationParameterEntryImmutable e in l.ParamList) {
AnalyticsExpirationParameters new_entry = new AnalyticsExpirationParameters(e);
_data[new_entry.security] = new_entry;
}
break;
}
Log.Gen.info($"AnalyticsParametersManager._on_exp_parameters count: {_data.Count}");
_assemble_and_publish();
// _bb.post(_out_exp_params_tag, new AnalyticsExpirationParametersMap(_data));
}
private void _assemble_and_publish() {
if (_data != null) {
SystemContractData sc_data = _bb.read_state(_in_contracts_tag);
if (sc_data != null) {
_bb.post(_out_exp_params_tag, new AnalyticsExpirationParametersMap(_data, sc_data));
}
}
}
#region IDisposable
public void Dispose() {
_bb.data_callback -= _on_bb_data;
foreach (IDisposable d in _disposables) {
d.Dispose();
}
}
#endregion
}
}
@@ -125,8 +125,8 @@ namespace mbts.spark {
if (_is_different(res)) {
_last_published = new OptionDriverPriceMap(_sec_tup.security_name, res);
var to_fire = new OptionDriverPriceMap(_sec_tup.security_name, res);
// bts.Log.Gen.info("SingleOptionDriverPricePublisher._compute_and_fire \n" +
// $"map:{to_fire.log_string()}");
bts.Log.Gen.info("SingleOptionDriverPricePublisher._compute_and_fire \n" +
$"map:{to_fire.log_string()}");
_logger.stop_default_timer();
_bb.post(SparkTags.OptionDriverBBOTag(_sec_tup.security_name),
new OptionDriverPriceMap(_sec_tup.security_name, res));
@@ -63,9 +63,9 @@ namespace mbts.spark {
vs_input, vs_nonvol_data.contracts, aux_data_map);
_timer.stop();
var tag_str = tag == null ? "Null" : tag.ToString();
// bts.Log.Gen.info($"SingleVolSurfaceCommittedOutputRetriever._recompute_and_publish " +
// $"vs_id: {_vs_id} time:{_timer.lastIntervalTime} ms tag:{tag_str} " +
// $"tid:{_tid()}"); //output: {vs_output.log_string()}*/");
bts.Log.Gen.info($"SingleVolSurfaceCommittedOutputRetriever._recompute_and_publish " +
$"vs_id: {_vs_id} time:{_timer.lastIntervalTime} ms tag:{tag_str} " +
$"tid:{_tid()}"); //output: {vs_output.log_string()}*/");
_logger.log(_log_id, _log_id, _timer.lastIntervalTime);
_bb.post(_out_bb_computed_vol_tag, vs_output);
}
@@ -1,19 +1,17 @@
namespace mbts.spark {
using bts;
using bts.api;
using bts.api.analytics;
using mbts.analytics;
using Spark.Core.Protobuf;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using mbts.analytics;
using bts;
using bts.api.analytics;
using System.Reactive.Linq;
using System.Threading;
using bts.api;
using System.Collections;
namespace mbts.spark {
// For a single VolSurface this class
// 1. Listents to commmits and calls the service to persist data
// 2. Gathers the vol surface input from the nw and publishes it
@@ -80,8 +78,11 @@
_snp_shot_map.Values);
}
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) =>
ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs.Volsurface.ToByteArray());
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) {
byte[] vs_bytes = vs.Volsurface.ToByteArray();
return
mbts.analytics.VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(vs_bytes);
}
private void _on_bb_data(object tag, object data) {
if (_in_bb_committ_tag.Equals(tag)) {
@@ -75,7 +75,7 @@ namespace mbts.spark {
var exp_price_map = OptionDriverPriceMap.get_vs_price_map(
all_sym_price_map, (s) => _option_symbols.Contains(s));
if (sc_data != null && vs_nonvol_input != null && exp_price_map != null) {
bts.Log.Gen.diag($"SingleVolSurfaceNonVolDataSource vs_id:{_vs_id} " +
bts.Log.Gen.info($"SingleVolSurfaceNonVolDataSource vs_id:{_vs_id} " +
"publishing VolSurfaceNonVolData");
_bb.post(_out_bb_vs_nonvol_data_tag,
new VolSurfaceNonVolData(
@@ -32,7 +32,7 @@ namespace mbts.spark {
public SingleVolSurfaceRequestCalculator(int vs_id, IEnumerable<string> symbols,
ThreadedBlackboard threaded_bb) {
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id: {vs_id}");
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator cons vs_id:{vs_id}");
_vs_id = vs_id;
_symbols = new HashSet<string>(symbols);
_bb = threaded_bb;
@@ -89,8 +89,8 @@ namespace mbts.spark {
effective_req.cascade_up,
effective_req.cascade_down);
_timer.stop();
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish time: " +
$"{_timer.lastIntervalTime}");
bts.Log.Gen.info($"SingleVolSurfaceRequestCalculator._recompute_and_publish time:" +
$"{_timer.lastIntervalTime} vs_output:{_last_output.log_string()}");
_bb.post(SparkTags.VolSurfaceCalculationResponseTag(_vs_id),
new VolSurfaceCalculationResponse(_last_output, effective_req.request_id));
}
@@ -11,22 +11,18 @@ namespace mbts.analytics {
// tags, into IReadOnlyDictionary of symbol vs data publsihed under one tag
public class SymbolAggregationPublisher<TData> : IDisposable {
private readonly ThreadedBlackboard _bb;
private readonly SecurityType _sec_type;
Func<string, ITag<TData>> _get_tag;
// the tag on which the output will be published
ITag<IReadOnlyDictionary<string, TData>> _out_tag;
private readonly ITag<SystemContractData> _sc_data_tag;
Func<string, ITag<TData>> _get_tag;
ITag<IReadOnlyDictionary<string, TData>> _out_tag;
private Dictionary<string, ITag<TData>> _tag_map =
new Dictionary<string, ITag<TData>>();
private HashSet<object> _obj_tags = new HashSet<object>();
private bool _dirty = true;
public SymbolAggregationPublisher(
ThreadedBlackboard bb,
SecurityType sec_type,
Func<string, ITag<TData>> get_tag,
ITag<IReadOnlyDictionary<string, TData>> out_tag) {
_bb = bb;
_sec_type = sec_type;
_get_tag = get_tag;
_out_tag = out_tag;
_sc_data_tag = SparkTags.SystemContractsTag;
@@ -52,20 +48,15 @@ namespace mbts.analytics {
return;
}
foreach (var st in sc_data.sectup_map) {
if (st.security_type != _sec_type) {
continue;
}
// this is not correct since it is assuming symbol/name is
// unique across securty_tuples
string symbol = st.security_name;
if (!_tag_map.ContainsKey(symbol)) {
var tag = _get_tag(symbol);
if (tag != null) {
_tag_map.Add(symbol, tag);
_obj_tags.Add(tag);
_bb.subscribe(tag);
_dirty = true;
}
var symbol_tag = _get_tag(symbol);
_tag_map.Add(symbol, symbol_tag);
_obj_tags.Add(symbol_tag);
_bb.subscribe(symbol_tag);
_dirty = true;
}
}
}
@@ -81,7 +72,7 @@ namespace mbts.analytics {
output.Add(symbol, symbol_data);
}
IReadOnlyDictionary<string, TData> ro_output = output;
bts.Log.Gen.diag($"SymbolAggregationPublisher._on_timer publishing " +
bts.Log.Gen.info($"SymbolAggregationPublisher._on_timer publishing " +
$"tag: {_out_tag} sz: {ro_output.Count}");
_bb.post(_out_tag, ro_output);
}
@@ -15,8 +15,6 @@ using System.Reactive.Linq;
using System.Collections;
using mbts.spark;
using System.DirectoryServices.ActiveDirectory;
using Spark.Core.Protobuf;
using mbts.ui;
// using mbts.bb;
namespace mbts.spark {
@@ -55,7 +53,6 @@ namespace mbts.spark {
// 2. Listens to the activation tag (also published by the UI) and
// creates the SingleVolSurfaceManager for the VS
public class VolSurfaceBusManager : IDisposable {
private List<IDisposable> _disps = new List<IDisposable>();
private ThreadedBlackboard _bb;
private bts.api.analytics.AnalyticsService _analytics_service;
// in tags
@@ -77,11 +74,10 @@ namespace mbts.spark {
private HighPerformanceTimer _timer = new HighPerformanceTimer();
public VolSurfaceBusManager(bts.api.IBus bus,
bts.api.analytics.AnalyticsService analytics_service,
bts.api.orderman.OrderService order_service) {
bts.api.analytics.AnalyticsService analytics_service) {
bts.Log.Ui.info("VSBusManager cons tid:{VolSurfaceTroubleshootingFunctions.tid()}");
_bus = bus;
_bb = new ThreadedBlackboard("AW2", bus);
_bb = new ThreadedBlackboard(bus);
_analytics_service = analytics_service;
// subs to bb
_bb.subscribe(_in_scdata_tag);
@@ -100,121 +96,48 @@ namespace mbts.spark {
.Subscribe(_on_vs_usage_update);
_subs.Add(vs_sub);
_subs.Add(vs_usage_sub);
_subs.Add(new AnalyticsParametersManager(bus, _analytics_service));
_subs.Add(new AnalyticsParametersManager(_bb, _analytics_service));
_subs.Add(new ResourceAllocator(bus, _bb));
_subs.Add(new SymbolAggregationPublisher<OptionDriverPriceMap>(
_bb, SecurityType.Option, sym => SparkTags.OptionDriverBBOTag(sym),
_bb, (sym) => SparkTags.OptionDriverBBOTag(sym),
SparkTags.AllOptionDriverBBOTag));
_subs.Add(new SymbolAggregationPublisher<OptionTheoInterpolationData>(
_bb, SecurityType.Option, sym => SparkTags.SymbolInterpGreeksTag(sym),
_bb, (sym) => SparkTags.SymbolInterpGreeksTag(sym),
SparkTags.AllInterpGreeks));
_subs.Add(new SymbolAggregationPublisher<ExpStrikeKeyedData<TheoPoint>>(
_bb, SecurityType.Option, sym => SparkTags.TC2Tags.LiveTheosTag(sym),
SparkTags.TC2Tags.AllLiveTheosTag));
_subs.Add(new LiveTheoPublisher(_bb));
_subs.Add(new InterpTheosServerPublisher(_bb, order_service));
_subs.Add(new VolSurfaceInterpGreeksMultiplexer(_bb));
// usage
var list_sub = _bus.subscribe(SparkTags.VolSurfaceListTag).OnDispatcher().Subscribe(t => {
VolSurfaceUsageList ulist = new VolSurfaceUsageList();
IDictionary<string, int> name_to_ids = new Dictionary<string, int>();
foreach (var kv in t) {
name_to_ids[kv.Value] = kv.Key;
//_subs.Add(new AnalyticsServiceTester(_bb));
// TODO: temporatily publish values
VolSurfaceUsageList ulist = new VolSurfaceUsageList();
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
VsId = 6,
SecTup = new bts.api.SecurityTuple() {
Type = SecurityType.Option,
Venue = VolSurfaceTemp.get_default_venue(SecurityType.Option, "BTC"),
Symbol = "BTC"
}
Log.Ui.info($"VolSurfaceUsageList name_to_ids count: {name_to_ids.Count}");
var vs_usage = mbts.config.Configuration.get<bts.config.toggles.VolSurfaceUsage>();
Log.Ui.info($"VolSurfaceUsageList vs_usage acount: {vs_usage.vol_surface_usage.Count}");
foreach (var u in vs_usage.vol_surface_usage) {
string option_name = u.option_name;
string vs_name = u.vs_name;
int vs_key;
if (name_to_ids.TryGetValue(vs_name, out vs_key)) {
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
VsId = vs_key,
SecTup = new bts.api.SecurityTuple {
Type = SecurityType.Option,
Venue = Venue.Deribit,
Symbol = option_name
}
});
} else {
Log.Gen.error($"Could not find vol surface with name: {vs_name}");
}
}
var list_imm = new VolSurfaceUsageListImmutable(ulist);
Log.Ui.info(list_imm.log_string());
_bb.post(SparkTags.VolSurfaceUsageTag, list_imm);
_spin_vss(list_imm);
});
_disps.Add(list_sub);
// f(contract keyed theos, securities) -> id keyed theos
// (so the newer UI controls can access theos vis sec keys)
var theo_sub =
_bus.subscribe(SparkTags.TC2Tags.AllLiveTheosTag)
.CombineLatest(bus.subscribe(SparkTags.SystemContractsTag),
(theos, sc_data) => (theos, sc_data)).Subscribe(
tup => {
var keyed_theos = _assemble_keyed_theos(tup.sc_data, tup.theos);
_bus.post(SparkTags.KeyedTheos, keyed_theos);
}
);
_disps.Add(theo_sub);
}
static IReadOnlyDictionary<uint, VolSurfaceTheoPoint> _assemble_keyed_theos(
SystemContractData sc_data,
IReadOnlyDictionary<string, ExpStrikeKeyedData<TheoPoint>> theos) {
if (sc_data is null || theos is null) {
return new Dictionary<uint, VolSurfaceTheoPoint>(0);
}
HighPerformanceTimer timer = new HighPerformanceTimer();
timer.start();
Dictionary<uint, VolSurfaceTheoPoint> rv = new Dictionary<uint, VolSurfaceTheoPoint>();
foreach (var kv in theos) {
var symbol = kv.Key;
ExpStrikeKeyedData<TheoPoint> sym_theos = kv.Value;
if (sym_theos == null)
continue;
foreach (var s_kv in sym_theos.get_data_linearly()) {
DateTime exp = s_kv.first;
double strike = s_kv.second;
TheoPoint tp = s_kv.third;
// TODO: fix exchange later
Tuple<uint?, uint?> keys =
sc_data.get_option_sec_id(Venue.Deribit, symbol, exp, strike);
if (keys != null) {
var c_key = keys.Item1;
var p_key = keys.Item2;
if (c_key.HasValue) {
rv[c_key.Value] = new VolSurfaceTheoPoint(tp, true);
}
if (p_key.HasValue) {
rv[p_key.Value] = new VolSurfaceTheoPoint(tp, false);
}
}
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
VsId = 7,
SecTup = new bts.api.SecurityTuple() {
Type = SecurityType.Option,
Venue = VolSurfaceTemp.get_default_venue(SecurityType.Option, "ETH"),
Symbol = "ETH"
}
}
timer.stop();
Log.Gen.info($"VolSurfaceBusManager keyed theos count: {rv.Count} " +
$"time: {timer.lastIntervalTime}");
return rv;
}
public ThreadedBlackboard bb() {
return _bb;
}
void _spin_vss(VolSurfaceUsageListImmutable ulist) {
foreach (var u in ulist.UsageList) {
var vs_id = u.VsId;
_bb.post(SparkTags.VolSurfaceActiveUITag(vs_id), true);
}
});
_bb.post(SparkTags.VolSurfaceUsageTag, new VolSurfaceUsageListImmutable(ulist));
}
void _on_vs_usage_update(Update<VolSurfaceUsageListImmutable, int> update) {
// TODO
return;
// int vs_count = update.all.Count();
// Log.Gen.info($"VSBusManager._on_vs_usage_update " +
// $"tid:{Thread.CurrentThread.ManagedThreadId} count:{update.all.Count()}");
// Log.assert(vs_count <= 1);
// if (update.all.TryGetSingle(out var to_write)) {
// _bb.post(SparkTags.VolSurfaceUsageTag, to_write);
// }
}
void _on_vss(bts.api.core.Update<VolSurfaceEntryImmutable, UInt64> update) {
@@ -249,7 +172,7 @@ namespace mbts.spark {
// callback
mbts.analytics.VolSurfaceSettings vs_settings = data as mbts.analytics.VolSurfaceSettings;
bts.Log.Gen.info(String.Format("VSBusManager._on_bb_update received vs creation tag vs:{0}",
ProtobufSerializationHelper.serialize_to_string(vs_settings)));
VolSurfaceUtilityFunctions.serialize_proto_to_text(vs_settings)));
_waiting_creations.Enqueue(vs_settings);
} else if (_in_bb_delete_tag.Equals(tag)) {
int vs_id = (int)data;
@@ -1,20 +0,0 @@
namespace mbts.analytics {
using mbts.spark;
// TheoPoint (from edge) has both calls and puts in the same structure.
// This shoudl dis-entangle that
public class VolSurfaceTheoPoint {
public readonly double theo = double.NaN;
public readonly double delta = double.NaN;
public readonly double driver = double.NaN;
public VolSurfaceTheoPoint(TheoPoint tp, bool is_call) {
if (tp != null) {
theo = is_call ? tp.fwd_normalized_call : tp.fwd_normalized_put;
delta = is_call ? tp.cdelta : tp.pdelta;
driver = tp.driver;
}
}
}
}
@@ -6,7 +6,6 @@
using mbts.user.settings;
using System;
using System.Collections.Generic;
public class VolSurfaceDisplayGridColumn : IEquatable<VolSurfaceDisplayGridColumn> {
public readonly Func<object, string> format;
@@ -19,19 +18,16 @@
VolSurfaceColumnSettings settings,
Func<object, string> format = null,
Func<string, object> parse = null,
Func<object, bool, object> tick_move = null,
IEqualityComparer<object> comparer = null) {
Func<object, bool, object> tick_move = null) {
this.settings = settings;
this.format = format ?? (v => v?.ToString() ?? string.Empty);
this.parse = parse ?? (v => v);
this.tick_move = tick_move ?? ((v, is_up) => v);
this.comparer = comparer ?? EqualityComparer<object>.Default;
}
public string unique_col_name => settings.id;
public string display_name => settings.display_name;
public string group => settings.group;
public IEqualityComparer<object> comparer { get; }
internal VolSurfaceColumnType type => settings.type;
@@ -7,7 +7,6 @@
using mbts.user.settings;
using System;
using System.Collections.Generic;
class VolSurfaceDisplayUtilities {
public static TickDisplaySettings default_tick_display =>
@@ -19,10 +18,6 @@
default_tick_display.with(display_multiplier: 100);
public static double parse_double(object obj) {
if (obj is null) {
Log.Gen.warn("parse_double received null input (will return nan and continue)");
return double.NaN;
}
Log.assert(obj is double);
obj = obj ?? Double.NaN;
double rv = obj is Double ? (double)obj : (Double.TryParse(obj.ToString(), out rv) ? rv : Double.NaN);
@@ -54,31 +49,9 @@
}
public static Func<object, bool, object> get_double_tickmove(TickFactors tick_factors, int tick_move) =>
(data, is_up) => {
if (data is not double dbl) {
return data;
}
if (dbl.is_nan()) {
return 0D;
}
return tick_factors.tick(dbl, is_up ? tick_move : -tick_move);
};
public static IEqualityComparer<double> get_double_comparer(
TickFactors tick_factors = null, double display_mult = double.NaN) {
if (tick_factors is null) {
return new TickFactors(10^7, 1).tick_equality_comparer();
}
// This equality comparer is used to compare actual values (not multiplied by
// 'display_mult'), while the TickFactors are used to format the display value (multiplied
// by 'display_mult'). Multiply the tick base by 'display_mult' so the equality comparison
// is done with the correct number of decimal places.
if (display_mult > 0 && Math.Log10(display_mult).is_int()) {
tick_factors = tick_factors.with(
tick_base: tick_factors.tick_base * display_mult);
}
return tick_factors.tick_equality_comparer();
}
(data, is_up) => data is double d_data ?
tick_factors.tick(d_data, is_up ? tick_move : -tick_move) :
data;
public static VolSurfaceDisplayGridColumn get_double_output_col(
string group,
@@ -140,10 +113,7 @@
col_config,
format: get_double_tostring(col_config.tick_factors, col_config.tick_display),
parse: get_parse_double(col_config.tick_factors, col_config.tick_display),
tick_move: get_double_tickmove(col_config.tick_factors, col_config.tick_move),
comparer: get_double_comparer(
col_config.tick_factors, col_config.tick_display.display_multiplier)
.cast<double, object>());
tick_move: get_double_tickmove(col_config.tick_factors, col_config.tick_move));
}
}
}
@@ -1,108 +0,0 @@
using System;
using System.Collections.Generic;
using mbts.analytics;
using bts.api;
using bts.collections;
using System.Linq;
using bts.api.orderman;
using bts;
namespace mbts.spark {
// Listens to the interp theos, decorates the data
// and sends them over to the sparkd server
public class InterpTheosServerPublisher : IDisposable {
private readonly ThreadedBlackboard _bb;
private readonly bts.api.orderman.OrderService _order_service;
private HighPerformanceTimer _timer = new HighPerformanceTimer();
public InterpTheosServerPublisher(ThreadedBlackboard bb,
bts.api.orderman.OrderService order_service) {
bts.Log.Ui.info(
$"InterpTheosServerPublisher cons tid:{VolSurfaceTroubleshootingFunctions.tid()}");
_bb = bb;
_order_service = order_service;
_bb.subscribe(SparkTags.AllInterpGreeks);
_bb.subscribe(SparkTags.SystemContractsTag);
_bb.data_callback += _on_data;
}
private void _on_data(object tag, object data) {
if (tag.Equals(SparkTags.SystemContractsTag) ||
tag.Equals(SparkTags.AllInterpGreeks)) {
_publish_data();
}
}
private static IDictionary<UInt32, DriverMD> _get_drivers(
IReadOnlyDictionary<string, OptionDriverPriceMap> driver_map,
SystemContractData sc_data) {
var rv = new Dictionary<UInt32, DriverMD>();
foreach (var kv in driver_map) {
rv.AddRange(
SecurityNormalizer.normalize_drivers(kv.Value, sc_data).ToArray());
}
return rv;
}
private static IEnumerable<Tuple<SecurityImmutable, TheoPoint>> _get_theos(
IReadOnlyDictionary<string, OptionTheoInterpolationData> theo_data,
SystemContractData sc_data) {
var rv = new List<Tuple<SecurityImmutable, TheoPoint>>();
foreach (var kv in theo_data) {
rv.AddRange(
SecurityNormalizer.normalize_interp_theos(kv.Value, sc_data));
}
return rv;
}
private void _publish_data() {
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag, null);
IReadOnlyDictionary<string, OptionTheoInterpolationData> all_theos =
_bb.read_state(SparkTags.AllInterpGreeks, null);
IReadOnlyDictionary<string, OptionDriverPriceMap> all_drivers =
_bb.read_state(SparkTags.AllOptionDriverBBOTag, null);
if (sc_data == null || all_theos == null || all_drivers == null)
return;
_timer.start();
IDictionary<UInt32, DriverMD> driver_map = _get_drivers(all_drivers, sc_data);
IEnumerable<Tuple<SecurityImmutable, TheoPoint>> theo_map = _get_theos(all_theos, sc_data);
// assemble it together and send it to the server
var ptp_list = new List<bts.api.orderman.PrecomputedTheoPoint>();
foreach (var tup in theo_map) {
SecurityImmutable sec = tup.Item1;
TheoPoint tp = tup.Item2;
bool is_call = sec.Option.CallPut == PutOrCall.Call;
var sec_id = sec.Id;
DriverMD dmd = null;
driver_map.TryGetValue(sec_id, out dmd);
PrecomputedTheoPoint ptp = new PrecomputedTheoPoint();
ptp.SecId = sec_id;
ptp.Driver = tp.driver;
ptp.DriverSecId = dmd != null && dmd.driver_security.HasValue ?
dmd.driver_security.Value.Id : 0;
ptp.Theo = is_call ? tp.call : tp.put;
ptp.Delta = is_call ? tp.cdelta : tp.pdelta;
ptp.Gamma = is_call ? tp.cgamma : tp.pgamma;
ptp.Vega = is_call ? tp.cvega : tp.pvega;
ptp.Theta = is_call ? tp.c_theta : tp.p_theta;
ptp.Rho = Double.NaN;
ptp_list.Add(ptp);
}
bts.api.orderman.PrecomputedTheos server_theos = new PrecomputedTheos();
server_theos.Theos.AddRange(ptp_list);
_timer.stop();
var comp_time = _timer.lastIntervalTime;
_timer.start();
_order_service.set_precomputed_theos(server_theos);
_timer.stop();
var pub_time = _timer.lastIntervalTime;
bts.Log.Gen.info($"InterpTheosServerPublisher._publish_data " +
$"size: {server_theos.Theos.Count} comp_time: {comp_time} msecs " +
$"pub_time: {pub_time}");
}
public void Dispose() {
_bb.data_callback -= _on_data;
}
}
}
+17 -80
View File
@@ -3,10 +3,6 @@ using System.Collections.Generic;
using mbts.analytics;
using bts.api;
using mbts.ui;
using MathNet.Numerics.Providers.FourierTransform;
using BCG;
using System.Windows.Automation;
using bts.collections;
namespace mbts.spark {
// Publishes theos for all options (on the side, also publishes the theos for TC2)
@@ -19,15 +15,12 @@ namespace mbts.spark {
private readonly HighPerformanceTimer _timer = new HighPerformanceTimer();
private readonly PerfStatsLogger _logger = new PerfStatsLogger(50, 100);
private readonly string _log_id = "LiveTheoPublisher";
private DateTime _last_future_theos_published = DateTime.MinValue;
private TimeSpan _futures_theos_publish_period = TimeSpan.FromMilliseconds(300);
public LiveTheoPublisher(ThreadedBlackboard bb) {
_bb = bb;
_bb.subscribe(_greeks_tag);
_bb.subscribe(_drivers_tag);
_bb.data_callback += _on_data;
_bb.timer_callback += _on_timer;
_interp_and_publish();
}
@@ -38,10 +31,6 @@ namespace mbts.spark {
}
}
private void _on_timer() {
_publish_future_theos();
}
private void _log_interpgreeks(
IReadOnlyDictionary<string, OptionTheoInterpolationData> interp_greeks) {
string log_msg = String.Empty;
@@ -70,14 +59,19 @@ namespace mbts.spark {
}
private void _log_theos(SystemContractData sc_data,
IReadOnlyDictionary<uint, GreeksTuple> greeks_map) {
IReadOnlyDictionary<uint, GreeksTuple> greeks_map,
DateTime? exp_filt = null) {
string rv = "LiveTheosPublisher data: ";
foreach (var kv in greeks_map) {
var id = kv.Key;
var g_tup = kv.Value;
if (sc_data.sec_md_map.TryGetValue(id, out var smd)) {
string sec_str = smd.ToString();
rv += "\n" + $"id: {id} sec: {sec_str} greeks: {g_tup}";
if (exp_filt == null ||
(smd.security.security_type() == SecurityType.Option &&
smd.security.Option.expiration_date().Equals(exp_filt.Value))) {
string sec_str = smd.ToString();
rv += "\n" + $"id: {id} sec: {sec_str} greeks: {g_tup}";
}
}
}
bts.Log.Gen.info(rv);
@@ -131,93 +125,36 @@ namespace mbts.spark {
return;
}
var k_theos = new Dictionary<SecurityStrike, TheoPoint>();
// option spreads
foreach (var kv in sc_data.strike_map) {
foreach (SecurityStrike k in kv.Value) {
var (call_id, put_id) = k.call_put_id;
var cp_id = k.call_put_id;
var driver = _get_option_driver(driver_map, k);
var tp = _interp_theo(interp_greeks, k, driver.get_driver());
k_theos[k] = tp;
// put it in the output map
if (call_id.HasValue) {
var normalized_theo = VolSurfaceCoreFunctions.normalize_theo(tp.call, tp.driver);
res.Add(call_id.Value,
if (cp_id.Item1.HasValue) {
res.Add(cp_id.Item1.Value,
new GreeksTuple(tp.vol, tp.driver, tp.call, tp.cdelta, tp.cgamma,
tp.cvega, tp.c_theta, Double.NaN, normalized_theo));
tp.cvega, tp.c_theta, Double.NaN));
}
if (put_id.HasValue) {
var normalized_theo = VolSurfaceCoreFunctions.normalize_theo(tp.put, tp.driver);
res.Add(put_id.Value,
if (cp_id.Item2.HasValue) {
res.Add(cp_id.Item2.Value,
new GreeksTuple(tp.vol, tp.driver, tp.put, tp.pdelta, tp.pgamma,
tp.pvega, tp.p_theta, Double.NaN, normalized_theo));
tp.pvega, tp.p_theta, Double.NaN));
}
}
}
// futures
var future_theos = _get_future_theos();
res.AddRange(future_theos);
// spreads, all option and future non tied spreads
foreach (var spr in sc_data.spreads) {
GreeksTuple gtup = StatelessSpreadCalculator.compute_non_tied_spread(spr.security, res);
res.Add(spr.security.Id, gtup);
}
// copy and publish
IReadOnlyDictionary<uint, GreeksTuple> res_ro = res;
bts.Log.Gen.info($"LiveTheoPublisher._interp_and_publish posting " +
$"count: {res_ro.Count}");
$"count: {res_ro.Count}");
_timer.stop();
_logger.log(_log_id, _log_id, _timer.lastIntervalTime);
_bb.post(SparkTags.Greeks, res_ro);
// oh and those TC2 theos for comptability
_publish_tc2_theos(k_theos);
}
// If we do any rolls like SP for futures, it will be here
IDictionary<UInt32, GreeksTuple> _get_future_theos() {
var rv = new Dictionary<UInt32, GreeksTuple>();
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag);
if (sc_data == null)
return rv;
foreach (var kv in sc_data.exp_map) {
var id = kv.Value;
SecurityMD sec_md;
if (sc_data.sec_md_map.TryGetValue(id, out sec_md)) {
if (sec_md.security.HasFuture) {
SecurityExpiration exp = kv.Key;
double pr = sec_md.md.fixing_price;
rv.Add(sec_md.security.Id,
new GreeksTuple(0, pr, pr, 1, 0, 0, 0, 0, pr));
}
}
}
return rv;
}
// recomputes and publishes them periodicially
void _publish_future_theos() {
if (DateTime.Now - _last_future_theos_published < _futures_theos_publish_period)
return;
_last_future_theos_published = DateTime.Now;
var rv = new Dictionary<SecurityExpiration, FutureTheoStructure>();
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag);
if (sc_data == null)
return;
foreach (var kv in sc_data.exp_map) {
var id = kv.Value;
SecurityMD sec_md;
if (sc_data.sec_md_map.TryGetValue(id, out sec_md)) {
if (sec_md.security.HasFuture) {
SecurityExpiration exp = kv.Key;
double pr = sec_md.md.fixing_price;
rv.Add(exp, new FutureTheoStructure(exp.expiration, pr, pr, 1, 0));
}
}
}
_bb.post(SparkTags.TC2Tags.LiveFutureTheosTag, rv);
}
public void Dispose() {
_bb.data_callback -= _on_data;
}
}
}
}
@@ -24,7 +24,7 @@ namespace mbts.spark {
var exp = kv.Key;
if (!temp.ContainsKey(kv.Key)) {
temp.Add(kv.Key,
new AnalyticsExpirationParameters(exp, null, empty, empty, 0, 0, 0, 0, 0));
new AnalyticsExpirationParameters(exp, empty, empty, empty, 0, 0, 0, 0, 0));
}
}
exp_map = temp;
@@ -1,50 +1,58 @@
#nullable enable
using System;
using System.Collections.Generic;
using mbts.analytics;
using bts.api;
using bts.api.persistence;
using System.Linq;
namespace mbts.spark {
using bts.api;
using mbts.analytics;
using System;
using System.Collections.Generic;
using System.Linq;
// All driver prices (along with some more info) for an option symbol
public class OptionDriverPriceMap {
public readonly string option_symbol;
public readonly IDictionary<SecurityExpiration, DriverMD> exp_price_map;
Dictionary<SecurityExpiration, DriverMD>? _unexpired_exp_price_map_backing;
public readonly String option_symbol = null;
public readonly IDictionary<SecurityExpiration, DriverMD> exp_price_map = null;
public OptionDriverPriceMap(
string option_symbol, IDictionary<SecurityExpiration, DriverMD> exp_price_map) {
this.option_symbol = option_symbol;
this.exp_price_map = exp_price_map;
string option_symbol_a,
IDictionary<SecurityExpiration, DriverMD> exp_price_map_a) {
option_symbol = option_symbol_a;
exp_price_map = exp_price_map_a;
}
public IDictionary<SecurityExpiration, DriverMD> unexpired_exp_price_map {
get {
return exp_price_map.Where(
kv => kv.Key.expiration >= DateTime.Now.Date).ToDictionary(
kv => kv.Key, kv => kv.Value);
}
}
public IDictionary<SecurityExpiration, DriverMD> unexpired_exp_price_map =>
_unexpired_exp_price_map_backing ??=
exp_price_map.Where(kv => kv.Key.expiration >= DateTime.Now.Date).ToDictionary();
// this is the BS needed because of ignoring exchange
public DriverMD get_driver_md(DateTime exp) =>
exp_price_map.FirstOrDefault(kv => kv.Key.expiration == exp).Value ?? DriverMD.empty;
public DriverMD get_driver_md(SecurityExpiration exp) =>
exp_price_map.GetValueOrDefault(exp) ?? DriverMD.empty;
public DriverMD get_driver_md(DateTime exp) {
foreach (var kv in exp_price_map) {
if (kv.Key.expiration == exp) {
return kv.Value;
}
}
return DriverMD.empty;
}
public DriverMD get_driver_md(SecurityExpiration exp) {
if (exp_price_map.TryGetValue(exp, out var d))
return d;
return DriverMD.empty;
}
public static IDictionary<VolSurfaceExpiration, DriverMD> get_vs_price_map(
IReadOnlyDictionary<string, OptionDriverPriceMap> all_sym_map,
Func<string, bool>? sym_filter = null
) {
sym_filter ??= _ => true;
return all_sym_map.SafeWhere(kv => kv.Value is not null && sym_filter(kv.Key))
.SelectMany(kv => kv.Value.exp_price_map)
.ToDictionaryCrushed(kv => kv.Key.to_vs_exp(), kv => kv.Value);
Func<string, bool> sym_filter = null) {
var rv = new Dictionary<VolSurfaceExpiration, DriverMD>();
if (all_sym_map != null)
foreach (var kv in all_sym_map) {
string sym = kv.Key;
OptionDriverPriceMap sym_map = kv.Value;
if (sym_filter == null || sym_filter(sym)) {
foreach (var kv_int in sym_map.exp_price_map) {
rv[new VolSurfaceExpiration(kv_int.Key)] = kv_int.Value;
}
}
}
return rv;
}
public IReadOnlyDictionary<SecurityExpiration, DriverMD> get_price_map() {
return new Dictionary<SecurityExpiration, DriverMD>(exp_price_map);
}
}
}
}
@@ -1,70 +0,0 @@
namespace mbts.spark {
using bts.api;
using System;
using System.Collections.Generic;
using System.Linq;
// A lot of options data (migrated from edge) is not normalized
// on the sec_id, but rather on a combination of symbol, exp, strike.
// Additionally the exchange is missing. This class serves as that
// one since point to resolve that.
// (Over time we will normalize all the data and this wont be needed)
public static class SecurityNormalizer {
// f(option_exp:driver_md) -> (sec_id:driver_md)
public static IDictionary<UInt32, DriverMD> normalize_drivers(
OptionDriverPriceMap driver_map, SystemContractData sc_data) {
if (driver_map is null) {
return new Dictionary<uint, DriverMD>(0);
}
Dictionary<UInt32, DriverMD> rv = new Dictionary<uint, DriverMD>();
foreach (var kv in driver_map.get_price_map()) {
var exp = kv.Key;
var dmd = kv.Value;
IEnumerable<SecurityMD> exp_secs = sc_data.get_securities(
(sec_md) => {
var s = sec_md.security;
return s.security_type() == SecurityType.Option &&
s.Symbol == driver_map.option_symbol &&
s.earliest_expiration() == exp.expiration;
}
);
foreach (var sec_md in exp_secs) {
rv.Add(sec_md.security.Id, kv.Value);
}
}
return rv;
}
public static IEnumerable<Tuple<SecurityImmutable, TheoPoint>> normalize_interp_theos(
OptionTheoInterpolationData symbol_theos, SystemContractData sc_data) {
if (symbol_theos is null) {
return Enumerable.Empty<Tuple<SecurityImmutable, TheoPoint>>();
}
var rv = new List<Tuple<SecurityImmutable, TheoPoint>>();
foreach (DateTime exp in symbol_theos.get_expirations()) {
Dictionary<double, Dictionary<double, TheoPoint>> exp_data =
symbol_theos.get_expiration_data(exp);
// exp_data is driver vs strike vs TP
foreach (var exp_kv in exp_data) {
foreach (var k_kv in exp_kv.Value) {
double strike = k_kv.Key;
TheoPoint tp = k_kv.Value;
IEnumerable<SecurityMD> calls = sc_data.get_options(
null, symbol_theos.symbol, exp, strike, PutOrCall.Call);
IEnumerable<SecurityMD> puts = sc_data.get_options(
null, symbol_theos.symbol, exp, strike, PutOrCall.Put);
foreach (SecurityMD sec_md in calls) {
rv.Add(Tuple.Create(sec_md.security, tp));
}
foreach (SecurityMD sec_md in puts) {
rv.Add(Tuple.Create(sec_md.security, tp));
}
}
}
}
return rv;
}
}
}
@@ -1,5 +1,4 @@
using System;
using System.Collections.Concurrent;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -108,22 +107,6 @@ namespace mbts.spark {
}
}
public SecurityImmutable? get_option_contract(
Venue venue, string symbol, DateTime exp, double strike, PutOrCall cp) {
var k_tup = get_option_sec_id(venue, symbol, exp, strike);
if (k_tup != null) {
var id = cp == PutOrCall.Call ? k_tup.Item1 : k_tup.Item2;
if (id.HasValue) {
var id_val = id.Value;
SecurityMD sec_md;
if (sec_md_map.TryGetValue(id_val, out sec_md)) {
return sec_md.security;
}
}
}
return null;
}
public Tuple<uint?, uint?> get_option_sec_id(
Venue venue, string symbol, DateTime exp, double strike) {
var s_exp = new SecurityExpiration(venue, SecurityType.Option, symbol, exp);
@@ -190,7 +173,7 @@ namespace mbts.spark {
}
IDictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> rv_data =
new Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>>();
return Tuple.Create(exp.to_security_expiration(type: SecurityType.Option), rv_data);
return Tuple.Create(exp.to_security_expiration(), rv_data);
}
internal IDictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> get_option_bbo(
@@ -199,11 +182,12 @@ namespace mbts.spark {
Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> rv =
new Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>>();
foreach (SecurityStrike k in strikes) {
var (call_id, put_id) = k.call_put_id;
// call
uint? call_id = k.call_put_id.Item1;
var call_sec_md = get_sec_md(call_id);
VolSurfaceMDUnit call_bbo = call_sec_md == null ? VolSurfaceMDUnit.empty : call_sec_md.Item2;
// put
uint? put_id = k.call_put_id.Item2;
var put_sec_md = get_sec_md(put_id);
VolSurfaceMDUnit put_bbo = put_sec_md == null ? VolSurfaceMDUnit.empty : put_sec_md.Item2;
rv.Add(k.strike, new Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>(call_bbo, put_bbo));
@@ -259,28 +243,5 @@ namespace mbts.spark {
kv.Value.Count > 0).Select(kv => kv.Key.expiration);
}
public IEnumerable<SecurityMD> spreads {
get {
return sec_md_map.Where(kv => kv.Value.security.HasSpread)
.Select(kv => kv.Value);
}
}
public IEnumerable<SecurityMD> get_securities(Func<SecurityMD, bool> criteria) {
return sec_md_map.Values.Where(sec_md => criteria(sec_md));
}
public IEnumerable<SecurityMD> get_options(
Venue? exchange, string option_name, DateTime? exp, double? strike, PutOrCall? cp) {
return get_securities(sc => {
var s = sc.security;
return s.security_type() == SecurityType.Option &&
(exchange == null || s.Exchange == exchange) &&
(exp == null || s.earliest_expiration() == exp) &&
(strike == null || s.strike() == strike) &&
(cp == null || s.Option.CallPut == cp);
});
}
}
}
@@ -22,7 +22,6 @@ namespace mbts.spark {
/// from the same secondary thread.
/// </summary>
public class ThreadedBlackboard {
private readonly string _bb_name;
private IBus _bus;
private List<IDisposable> _subs = new List<IDisposable>();
private HashSet<object> _tag_map = new HashSet<object>();
@@ -32,10 +31,9 @@ namespace mbts.spark {
private IDictionary<object, object> _cache = new
Dictionary<object, object>();
private static int _tid() { return VolSurfaceTroubleshootingFunctions.tid(); }
public ThreadedBlackboard(string name, IBus bus) {
bts.Log.Ui.info($"ThreadedBlackBoard.cons tid:{_tid()} bb_name: {name}");
public ThreadedBlackboard(IBus bus) {
bts.Log.Ui.info($"ThreadedBlackBoard.cons tid:{ _tid()}");
_bus = bus;
_bb_name = name;
subscribe(SparkTags.SparkTimer);
System.Threading.Thread timer_thread = new System.Threading.Thread(() => {
DateTime start_time = DateTime.Now;
@@ -63,13 +61,15 @@ namespace mbts.spark {
return;
}
_tag_map.Add(tag);
bts.Log.Ui.info($"ThreadedBlackBoard.subscribe tag:{tag} tid:{_tid()}");
bts.Log.Ui.info($"ThreadedBlackBoard.subscribe tag:{tag} tid:{ _tid()}");
var observable = _bus.subscribe(tag).OnDispatcher().Subscribe(
data => _on_bus_data(tag, data));
_subs.Add(observable);
}
public void post<T>(ITag<T> tag, T data, bool block_until_written = false) {
bts.Log.Ui.diag($"ThreadedBlackBoard.post tag:{tag} data:{_data_string(data)} " +
$"tid:{_tid()}");
_cache[tag] = data;
_bus.post(tag, data);
}
@@ -92,6 +92,8 @@ namespace mbts.spark {
timer_callback();
return;
}
bts.Log.Ui.diag($"ThreadedBlackBoard._on_bus_data tag:{tag} data:{_data_string(data)} " +
$"tid:{_tid()}");
data_callback(tag, data);
}
@@ -1,25 +1,17 @@
using bts.api;
using bts.api.analytics;
using bts.collections;
using bts.utils;
using IronPython.Compiler.Ast;
using mbts;
using mbts.analytics;
using mbts.spark;
using mbts.ui.controls;
using mbts.ui.converters;
using mbts.ui.shell;
using Spark.Core;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using mbts;
using mbts.analytics;
using mbts.ui.controls;
using mbts.ui.shell;
using mbts.spark;
using bts.utils;
using bts.api;
using bts.collections;
using System.Collections.Immutable;
namespace mbts.spark {
/// This contains the list of global values for the vol
@@ -63,27 +55,6 @@ namespace mbts.spark {
return rv;
}
public static string log_string(this VolSurfaceCalculationRequest vs_req) {
if (vs_req == null) {
return "Null";
}
string action_str = String.Empty;
foreach (var kv in vs_req.action_map) {
action_str += $"exp: {kv.Key.ToString()} action: {kv.Value.ToString()}, ";
}
action_str = action_str.TrimEnd(',', ' ');
return $"vs_inp: {vs_req.volsurface_input.log_string()}\nreq_id: {vs_req.request_id}\n" +
$"action_map: {action_str}\nup: {vs_req.cascade_up} down: {vs_req.cascade_down}";
}
public static string log_string(this VolSurfaceCalculationResponse resp) {
if (resp == null) {
return "Null";
}
return $"req_id: {resp.request_id} vs_output: " +
$"{resp.volsurface_calculation_output.volsurface_input.log_string()}";
}
private static string _trim_leading_char(string s, char c) {
if (!s.is_null_or_empty() && s.EndsWith(c)) {
return s.Remove(s.Length - 1, 1);
@@ -92,12 +63,11 @@ namespace mbts.spark {
}
internal static string log_string(this VolSurfaceDisplayModel.DisplayModelData dm_data) {
var vs_output = dm_data.vs_output;
var exp_grid = dm_data.exp_grid;
var vs_output_str = vs_output == null ? "NULL" : vs_output.volsurface_input.log_string();
var exp_grid_str = exp_grid == null ? "NULL" : exp_grid.log_string();
var rv = $"DisplayModelData\nvs_output:\n{vs_output_str}\n" +
$"exp_grid\n{exp_grid_str}\n";
string rv = String.Empty;
string global_grid_str = dm_data.global_grid == null ? "Null" : dm_data.global_grid.log_string();
rv += $"global_grid: {global_grid_str} \n";
string exp_grid_str = dm_data.exp_grid == null ? "Null" : dm_data.exp_grid.log_string();
rv += $"exp_grid: {exp_grid_str} \n";
return rv;
}
@@ -113,19 +83,19 @@ namespace mbts.spark {
}
internal static string log_string(this VolSurfaceDisplayGrid dgrid) {
Func<IDictionary<string, object>, string> log_exp = (col_val_map) => {
Func<IDictionary<string, object>, string> log_exp = (map) => {
string rv = String.Empty;
foreach (var kv in col_val_map) {
foreach (var kv in map) {
string val_string = kv.Value == null ? "Null" : kv.Value.ToString();
rv += $"{kv.Key}: {val_string}, ";
rv += $"{kv.Key}:{val_string},";
}
return _trim_leading_char(rv, ',');
};
string rv = String.Empty;
foreach (var kv in dgrid.data_map) {
rv += $"Exp: {kv.Key.expiration.ToShortDateString()} Data: {log_exp(kv.Value)}\n";
rv += $"Exp:{kv.Key.expiration.ToShortDateString()} Data:{log_exp(kv.Value)},";
}
return rv;
return _trim_leading_char(rv, ',');
}
internal static string log_string(this OptionDriverPriceMap map) {
@@ -162,7 +132,7 @@ namespace mbts.spark {
internal static string log_string(this Theos t) {
string rv = $"strike: {t.strike} fwd: {t.fwd} driver: {t.driver} " +
$"move: {t.move} vol: {t.vol} c_theo: {t.call} " +
$"move: { t.move} vol: {t.vol} c_theo: {t.call} " +
$"p_theo: {t.put}";
return rv;
}
@@ -181,8 +151,8 @@ namespace mbts.spark {
foreach (var kv in sc_data.strike_map) {
var exp = kv.Key;
foreach (var k in kv.Value) {
rv += $"exp: {exp} k: {k} c_id: {k_id(k.call_put_id.call)} " +
$"p_id: {k.call_put_id.put}" + "\n";
rv += $"exp: {exp} k: {k} c_id: {k_id(k.call_put_id.Item1)} " +
$"p_id: {k.call_put_id.Item2}" + "\n";
}
}
return rv;
@@ -208,67 +178,6 @@ namespace mbts.spark {
return rv;
}
internal static string log_string(this ComboFullData cf_data) {
string rv = String.Empty;
if (cf_data.option_expirations != null) {
foreach (var kv in cf_data.option_pos_map) {
var exp = kv.Key;
foreach (var kv_in in kv.Value) {
double k = kv_in.Key;
ComboStrikeData kp = kv_in.Value;
rv += $"exp: {exp.ToString()} k: {k} Pos: {kp.call_pos},{kp.put_pos} ({kp.call_raw_pos},{kp.put_raw_pos}) ";
}
}
}
if (cf_data.future_pos_map != null) {
foreach (var kv in cf_data.future_pos_map) {
rv += $"exp: {kv.Key.ToString()} {kv.Value.Item1},{kv.Value.Item2} ";
}
}
return rv;
}
internal static string log_string(this SlideFullData sl_data) {
Func<SlideGreekUnitKey, string> sguk_str = (sguk) => sguk.display_name;
Func<SlideGreekUnit, string> sgu_str = (sgu) => {
if (sgu == null)
return "No Handles";
string rv = $"Handle: {sgu.driver_price} ";
foreach (double d in sgu.position_greeks)
rv += $"{d}, ";
rv = rv.Trim();
if (rv.EndsWith(","))
rv = rv.TrimEnd(',');
return rv;
};
string rv = String.Empty;
foreach (var kv in sl_data.map) {
rv += $"SlideGreekUnitKey: {sguk_str(kv.Key)}\n";
foreach (var i_kv in kv.Value) {
rv += sgu_str(i_kv.Value) + "\n";
}
}
rv += $"Overriden?: {sl_data.ui_override != null}";
return rv;
}
internal static string log_string(this VolSurfaceUsageListImmutable vsu_list) {
string rv = "VolSurfaceUsageList:";
foreach (var u in vsu_list.UsageList) {
rv += $" {u.SecTup.Symbol}:{u.VsId}";
}
return rv;
}
internal static string log_string(this IPNLUnit p) {
string rv = "IPNLUnit:";
rv += $" account: {p.account} sec: {p.security.security_desc()} driver: {p.driver} theo: {p.theo} settle: {p.settle_price}" +
$" start_pos: {p.start_long_pos - p.start_short_pos} day_pos: {p.day_long_pos - p.day_short_pos}" +
$" start_pnl: {p.start_pnl} start_delta: {p.start_delta} start_vega: {p.start_vega}" +
$" day_pnl: {p.day_pnl} day_delta: {p.day_delta} day_vega: {p.day_vega}";
return rv;
}
internal static int tid() {
return System.Threading.Thread.CurrentThread.ManagedThreadId;
}
@@ -86,14 +86,9 @@ namespace mbts.spark {
}
private void _save_exp_params() {
var api_driver = new ExpirationDriverImmutable(new() {
Security = driver_exp.to_api_sec_exp()
});
var exp_params = new AnalyticsExpirationParameters[] {
new AnalyticsExpirationParameters(
option_exp1, api_driver, driver_exp, driver_exp, 0, 0, double.NaN, 1, 1),
new AnalyticsExpirationParameters(
option_exp2, api_driver, driver_exp, driver_exp, 0, 0, double.NaN, 1, 1),
var exp_params = new AnalyticsExpirationParameters[]{
new AnalyticsExpirationParameters(option_exp1, driver_exp, driver_exp, driver_exp, 0, 0, Double.NaN, 1, 1),
new AnalyticsExpirationParameters(option_exp2, driver_exp, driver_exp, driver_exp, 0, 0, Double.NaN, 1, 1),
};
_bb.post(SparkTags.ExpirationParametersCommitTag, exp_params);
}
@@ -108,4 +103,4 @@ namespace mbts.spark {
}
#endregion
}
}
}
@@ -31,24 +31,11 @@ namespace mbts.ui.controls {
VolSurfaceExpiration exp = p.Key;
VolCurveOutput exp_output = p.Value;
IDictionary<VolSurfaceDisplayGridColumn, object> out_exp_map = VolSurfaceUIAdapterUtils.get_exp_data(ref out_grid, exp);
out_exp_map[_fwd_col] = exp_output?.fwd ?? double.NaN;
out_exp_map[_ref_fwd_col] = exp_output
?.adjusted_curve_parameters
?.core_parameters
?.ref_forward
?? double.NaN;
out_exp_map[_live_driver_col] = exp_output
?.aux_data
?.driver_price
?? double.NaN;
out_exp_map[_driver_override_col] = exp_output
?.adjusted_curve_parameters
?.core_parameters
?.driver_override
?? double.NaN;
out_exp_map[_fwd_col] = exp_output == null ? Double.NaN : exp_output.fwd;
out_exp_map[_ref_fwd_col] = exp_output != null && exp_output.adjusted_curve_parameters != null && exp_output.adjusted_curve_parameters.core_parameters != null ?
exp_output.adjusted_curve_parameters.core_parameters.ref_forward : Double.NaN;
out_exp_map[_live_driver_col] = (exp_output != null && exp_output.aux_data != null) ? exp_output.aux_data.driver_price : Double.NaN;
out_exp_map[_driver_override_col] = exp_output.adjusted_curve_parameters.core_parameters.driver_override;
}
}
@@ -3,16 +3,15 @@ namespace mbts.spark {
using mbts.ui;
using mbts.ui.controls.graph;
using mbts.ui.shell;
using ProtoBuf;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
[ProtoContract]
class VolSurfaceGraphSettings : IProtobuf<VolSurfaceGraphSettings> {
class VolSurfaceGraphSettings : IEquatable<VolSurfaceGraphSettings>, ICloneable {
public static VolSurfaceGraphSettings get_default() {
return new VolSurfaceGraphSettings {
put_control_points = new ScatterSeriesSettings {
@@ -110,8 +109,8 @@ namespace mbts.spark {
// }
//}
public VolSurfaceGraphSettings Clone() =>
ProtobufSerializationHelper.clone(this);
public object Clone() =>
ProtoBufSerializationHelper.clone_protobuf(this);
public bool Equals(VolSurfaceGraphSettings other) =>
other != null &&
@@ -6,10 +6,6 @@ using mbts.analytics;
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core;
using Spark.Core.Disposables;
using Spark.Core.Collections;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -55,7 +51,7 @@ namespace mbts.spark {
var vs_removes = removed.Select(exp => exp.ToVSExp());
var true_removed = removed.Where(rmv => !vs_adds.Contains(rmv.ToVSExp()));
var true_added = added.Except(vs_removes.Concat(_hidden_exps), v => v.ToVSExp());
var true_added = added.Where(add => !vs_removes.Contains(add.ToVSExp()));
var changed_calc_modes = added.Where(add => vs_removes.Contains(add.ToVSExp()));
foreach (var tr in true_removed) {
@@ -65,10 +61,16 @@ namespace mbts.spark {
}
}
var comp = ComparerWrapper<object>.wrap_cast(
NullCheckComparer.create<IExpirationBasedRow>(
(r1, r2) => r1.expiration.CompareTo(r2.expiration)));
visible_rows.InsertSorted(true_added, comp);
foreach (var ta in true_added) {
if (_hidden_exps.Contains(ta.ToVSExp()) ||
!rows.TryGetFirst(r => r.expiration.expiration == ta.expiration, out var row)) {
continue;
}
visible_rows.InsertSorted(row,
Comparer<IExpirationBasedRow>.Create(
(r1, r2) => r1.expiration.CompareTo(r2.expiration))
.wrap<IExpirationBasedRow, object>());
}
foreach (var ccm in changed_calc_modes) {
int index = visible_rows
@@ -10,10 +10,6 @@ namespace mbts.spark {
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Analytics.View;
using Spark.Core.Disposables;
using Spark.Core.Protobuf;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -31,13 +27,13 @@ namespace mbts.spark {
readonly LinearAxisVM _x_axis = new() { position = AxisPosition.BottomLeftToRight };
readonly LinearAxisVM _y_axis = new() { position = AxisPosition.LeftBottomToTop };
readonly Dictionary<SecurityExpiration, ExpGraphBounds> _expiration_graph_bounds;
readonly VolSurfaceGraphSettings _settings;
readonly ObservableCollection<VolSurfaceDisplayGridExpiration> _expirations = new();
readonly Dictionary<VolSurfaceDisplayGridExpiration, SeriesSetVM> _expiration_series_cache = new();
VolSurfaceExpiration _md_exp;
VolSurfaceDisplayGridExpiration _expiration;
VolSurfaceDisplayGridExpiration _earliest_selected_expiration;
VolSurfaceGraphSettings _settings;
object _implied_vol_market_side = ImpliedVolHelper.None;
bool _show_vol_path;
@@ -50,9 +46,7 @@ namespace mbts.spark {
if (startup_data.vol_curve_x_axis == null) {
var x_axis = BTSOxyGraphAxisDouble.Default;
x_axis.name = "Strike";
x_axis.axis_line_color = BTSColors.Graph.axis_line;
x_axis.major_grid_line_color = BTSColors.Graph.grid_line;
x_axis.tick_line_color = BTSColors.Graph.tick_line;
x_axis.position = AxisPosition.BottomLeftToRight;
x_axis.minimum = 0;
x_axis.maximum = 2000;
@@ -64,9 +58,7 @@ namespace mbts.spark {
if (startup_data.vol_curve_y_axis == null) {
var y_axis = BTSOxyGraphAxisDouble.Default;
y_axis.name = "Volatility";
y_axis.axis_line_color = BTSColors.Graph.axis_line;
y_axis.major_grid_line_color = BTSColors.Graph.grid_line;
y_axis.tick_line_color = BTSColors.Graph.tick_line;
y_axis.position = AxisPosition.LeftBottomToTop;
y_axis.minimum = 0;
y_axis.maximum = 1;
@@ -86,17 +78,13 @@ namespace mbts.spark {
if (_model.get_active_settings() is not VolSurfaceSettings vss) {
return null;
}
var vm = new VolSurfaceGraphSettingsVM(vss.core_settings.vol_surface_name);
vm.load_from(_settings.Clone());
vm.request_commit += commit;
return new VolSurfaceGraphSettingsWindow {
DataContext = vm
};
void commit(VolSurfaceGraphSettings settings) {
_settings = settings;
_recreate_series();
}
// return new VolSurfaceGraphSettingsEditor {
// DataContext = new VolSurfaceGraphSettingsEditorVM(vss.core_settings.vol_surface_name, ProtoBufSerializationHelper.clone_protobuf(_settings), settings => {
// _settings = settings;
// _recreate_series();
// })
// };
return null;
});
graph_vm = new BTSGraphVM {
plot_area_background = Colors.Transparent,
@@ -125,7 +113,7 @@ namespace mbts.spark {
})
.BufferLatest(TimeSpan.FromSeconds(0.1))
.OnDispatcher()
.SelectSeries(series => Observable.Create<SeriesVM>(o => {
.SelectManyInSeries(series => Observable.Create<SeriesVM>(o => {
o.OnNext(null);
return Disposable.Create(series
.Select(svm => svm.points.Subscribe((s, e) => o.OnNext(svm)))
@@ -193,20 +181,6 @@ namespace mbts.spark {
static (double call_wing_start, double put_wing_start) _get_actual_wing_starts(VolCurveDisplayGraph disp_graph) =>
disp_graph.all_points.Select(p => p.Item1).MinMax() ?? (double.NaN, double.NaN);
void _recreate_series() {
/// 'graph_vm.series_set' is bound to '_expirations', so clearing and re-adding expirations
/// in turn regenerates the series. '_expiration_series_cache' must
/// be cleared as well, otherwise cached series vms would just be back to the collection
/// ('graph_vm.series_set').
var visible_exp = _earliest_selected_expiration;
_expiration_series_cache.Clear();
_expirations.SetItems(_model.get_ordered_expirations());
foreach (var svm in graph_vm.series.OfType<SeriesSetVM>()) {
svm.is_visible = svm.args.Equals(visible_exp);
}
_update();
}
void _expirations_changed(IEnumerable<VolSurfaceDisplayGridExpiration> added, IEnumerable<VolSurfaceDisplayGridExpiration> removed) {
_expirations.sync_with(_model.get_ordered_expirations());
_update();
@@ -0,0 +1,84 @@
namespace mbts.spark {
using mbts.ui;
using mbts.ui.shell;
using System;
using System.Reactive.Linq;
using System.Windows.Input;
class VolGridCellVM : DisposableViewModelBase {
readonly Property<object> _candidate_value;
readonly Property<object> _committed_value;
readonly Property<bool> _is_dirty;
public VolGridCellVM(string column_id) {
this.column_id = column_id ?? throw new ArgumentNullException(nameof(column_id));
_committed_value = backing<object>(nameof(committed_value));
_candidate_value = backing<object>(nameof(candidate_value));
_is_dirty = backing(nameof(is_dirty),
_committed_value.observe_current(true)
.CombineLatest(_candidate_value.observe_current(true))
.Select(tup => !Equals(tup.First, tup.Second))
.OnDispatcher());
}
public string column_id { get; }
public object committed_value {
get => _committed_value.Value;
set => _committed_value.set(value);
}
public object candidate_value {
get => _candidate_value.Value;
set => _candidate_value.set(value);
}
public bool is_dirty => _is_dirty.Value;
public IObservable<object> observe_candidate(bool start_immediately = false) =>
_candidate_value.observe_current(start_immediately);
public void revert() =>
candidate_value = committed_value;
public override string ToString() =>
$"column_id: {column_id}, committed: {committed_value}, candidate: {candidate_value}";
}
class VolGridCellVM<T> : VolGridCellVM {
public VolGridCellVM(string column_id) : base(column_id) { }
public VolGridCellVM(string column_id, T committed_value, T candidate_value) : base(column_id) {
this.committed_value = committed_value;
this.candidate_value = candidate_value;
}
public new T committed_value {
get => base.committed_value is T v ? v : default;
set => base.committed_value = value;
}
public new T candidate_value {
get => base.candidate_value is T v ? v : default;
set => base.candidate_value = value;
}
}
class VolGridTickCellVM : VolGridCellVM {
ICommand _tick_up_cmd;
ICommand _tick_down_cmd;
public VolGridTickCellVM(string column_id) : base(column_id) { }
public event Action<bool> request_tick;
public ICommand tick_up_cmd =>
_tick_up_cmd ??= new DelegateCommand(() =>
request_tick?.Invoke(true));
public ICommand tick_down_cmd =>
_tick_down_cmd ??= new DelegateCommand(() =>
request_tick?.Invoke(false));
}
}
@@ -1,11 +0,0 @@
#nullable enable
namespace mbts.spark.VolSurface {
using System.Windows.Media;
readonly struct VolSurfaceCellState {
public bool is_dirty => committed_text is not null;
public FormattedText? text { get; init; }
public FormattedText? committed_text { get; init; }
}
}
@@ -1,80 +0,0 @@
#nullable enable
namespace mbts.spark {
using bts;
using mbts.ui.controls;
using mbts.ui.shell;
using Spark.Core;
using System;
class VolSurfaceCellVM : DisposableViewModelBase {
readonly Property<object?> _candidate_value;
readonly Property<object?> _committed_value;
readonly DelegateProperty<bool> _is_dirty;
readonly DeferrableAction _refresh;
public VolSurfaceCellVM(
VolSurfaceDisplayGridExpiration expiration, VolSurfaceDisplayGridColumn column) {
this.column = column ?? throw new ArgumentNullException(nameof(column));
this.expiration = expiration ?? throw new ArgumentNullException(nameof(expiration));
_committed_value = backing<object?>(nameof(committed_value), column.comparer);
_candidate_value = backing<object?>(nameof(candidate_value), column.comparer);
_is_dirty = backing(
nameof(is_dirty), () => !column.comparer.Equals(candidate_value, committed_value));
_refresh = new(_is_dirty.refresh);
_committed_value.Changed += on_committed_changed;
_candidate_value.Changed += on_candidate_changed;
_is_dirty.Changed += (o, n) => {
Log.assert(o != n);
// TODO: John, this was logged too many times
// Log.Ui.info(
// $"VolSurface '{expiration}.{column}' is_dirty changed to {n}. " +
// $"commited: {committed_value}; candidate: {candidate_value}");
};
void on_committed_changed(object? oldval, object? newval) =>
_is_dirty.refresh();
void on_candidate_changed(object? oldval, object? newval) =>
_is_dirty.refresh();
}
public event PropertyChange<object?>? candidate_value_changed {
add => _candidate_value.Changed += value;
remove => _candidate_value.Changed -= value;
}
public VolSurfaceDisplayGridColumn column { get; }
public string column_id => column.unique_col_name;
public VolSurfaceDisplayGridExpiration expiration { get; }
public object? committed_value {
get => _committed_value.Value;
set => _committed_value.set(value);
}
public object? candidate_value {
get => _candidate_value.Value;
set => _candidate_value.set(value);
}
public bool is_dirty => _is_dirty.Value;
public IObservable<object?> observe_candidate(bool start_immediately = false) =>
_candidate_value.observe_current(start_immediately);
public void reset(object? committed_value, object? candidate_value) {
using var _ = _refresh.defer();
this.committed_value = committed_value;
this.candidate_value = candidate_value;
}
public void revert() =>
candidate_value = committed_value;
public override string ToString() =>
$"column: {column}, committed: {committed_value}, candidate: {candidate_value}";
}
}
@@ -26,7 +26,7 @@ namespace mbts.spark.VolSurface {
id = key ?? throw new InvalidOperationException("Column key cannot be null");
}
public VolSurfaceDisplayGridColumn model { get; }
public VolSurfaceDisplayGridColumn model { get; set; }
public VolSurfaceColumnType type => model.type;
public new VolSurfaceColumnSettings create() {
@@ -43,7 +43,7 @@ namespace mbts.spark.VolSurface {
static Thickness _header_cell_padding => new(6, 0, 4, 0);
IValueConverter _data_context_converter =>
ValueConverter.create<VolSurfaceRowVM, object>(row => row?.get_cell(model));
ValueConverter.create<VolSurfaceRowContext, object>(row => row?.get_cell(model));
public override FrameworkElement view_factory() {
return type switch {
@@ -58,7 +58,7 @@ namespace mbts.spark.VolSurface {
HorizontalAlignment = HorizontalAlignment.Left,
Foreground = BTSColors.header_text.to_brush(),
};
text.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceRowVM.expiration)));
text.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceRowContext.expiration)));
var bd = new Border {
HorizontalAlignment = HorizontalAlignment.Stretch,
Padding = _header_cell_padding,
@@ -73,12 +73,12 @@ namespace mbts.spark.VolSurface {
var view = new TextBlock {
HorizontalAlignment = HorizontalAlignment.Right,
Margin = _cell_padding,
Foreground = BTSColors.VolSurfaceGrid.readonly_column_foreground
Foreground = Brushes.Blue,
};
view.SetBinding(FrameworkElement.DataContextProperty, new Binding() {
Converter = _data_context_converter
});
view.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceCellVM.candidate_value)) {
view.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolGridCellVM.candidate_value)) {
Converter = ValueConverter.create(obj => model.format(obj))
});
return view;
@@ -101,16 +101,16 @@ namespace mbts.spark.VolSurface {
view.SetBinding(FrameworkElement.DataContextProperty, new Binding() {
Converter = _data_context_converter
});
view.SetBinding(VolSurfaceCellView.CommittedValueProperty, new Binding(nameof(VolSurfaceCellVM.committed_value)) {
view.SetBinding(VolSurfaceCellView.CommittedValueProperty, new Binding(nameof(VolGridCellVM.committed_value)) {
Mode = BindingMode.OneWay,
Converter = ValueConverter.create(obj => model.format(obj))
});
view.SetBinding(VolSurfaceCellView.CandidateValueProperty, new Binding(nameof(VolSurfaceCellVM.candidate_value)) {
view.SetBinding(VolSurfaceCellView.CandidateValueProperty, new Binding(nameof(VolGridCellVM.candidate_value)) {
Mode = BindingMode.TwoWay,
Converter = ValueConverter.create<object, string>(obj => model.format(obj), obj => model.parse(obj))
});
view.SetBinding(VolSurfaceCellView.TickDownCommandProperty, new Binding(nameof(VolSurfaceTickCellVM.tick_down_cmd)));
view.SetBinding(VolSurfaceCellView.TickUpCommandProperty, new Binding(nameof(VolSurfaceTickCellVM.tick_up_cmd)));
view.SetBinding(VolSurfaceCellView.TickDownCommandProperty, new Binding(nameof(VolGridTickCellVM.tick_down_cmd)));
view.SetBinding(VolSurfaceCellView.TickUpCommandProperty, new Binding(nameof(VolGridTickCellVM.tick_up_cmd)));
var bd = new Border {
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
@@ -1,5 +1,4 @@
#nullable enable
namespace mbts.spark.VolSurface {
namespace mbts.spark.VolSurface {
using bts;
using bts.collections;
using bts.utils;
@@ -12,10 +11,6 @@ namespace mbts.spark.VolSurface {
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core;
using Spark.Core.Disposables;
using Spark.Core.Collections;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -30,20 +25,17 @@ namespace mbts.spark.VolSurface {
class VolSurfaceGridVM : DisposableViewModelBase {
readonly VolSurfaceVM _parent;
readonly ObservableCollection<VolSurfaceDisplayGridExpiration> _expirations = new();
readonly DeferrableAction _invalidate_rows;
readonly DeferrableActionWrapper _invalidate_rows;
readonly ColumnsModel _columns_model;
ISet<string> _hidden_columns;
ISet<VolSurfaceExpiration>? _hidden_expirations;
IDisposable? _shift_editor;
ISet<VolSurfaceExpiration> _hidden_expirations;
IDisposable _shift_editor;
public VolSurfaceGridVM(
VolSurfaceVM vm,
VolSurfaceDisplayModel model,
ISet<string> hidden_columns,
ISet<VolSurfaceExpiration> hidden_expirations) {
Log.notnull(hidden_columns);
Log.notnull(hidden_expirations);
public VolSurfaceGridVM(VolSurfaceVM vm, VolSurfaceDisplayModel model,
ISet<string> hidden_columns, ISet<VolSurfaceExpiration> hidden_expirations) {
Log.assert(hidden_columns != null);
Log.assert(hidden_expirations != null);
_parent = vm;
this.model = model;
_columns_model = new(create_exp_column_view());
@@ -71,31 +63,16 @@ namespace mbts.spark.VolSurface {
};
_dispose = Disposable.Create(
ObservableAutoWrapper.connect(_expirations, rows, row_factory),
ObservableAutoWrapper.connect_item_hooks(rows, connect_row),
ObservableAutoWrapper.connect(_expirations, rows, exp => new VolSurfaceRowContext(this, exp), row => row.Dispose()),
sorted_visible_rows.bind(visible_rows),
Disposable.Create(() => {
this.model.on_candidate_grid_change -= _on_grid_updated;
this.model.on_committed_grid_change -= _on_grid_updated;
rows.DisposeAll(true);
Disposable.dispose(rows);
Disposable.dispose(ref _shift_editor);
}),
_columns_model);
VolSurfaceRowVM row_factory(VolSurfaceDisplayGridExpiration exp) =>
new(this, exp);
IDisposable connect_row(VolSurfaceRowVM row) {
row.request_calculate += request_recalc;
return Disposable.Create(() => {
row.request_calculate -= request_recalc;
row.Dispose();
});
void request_recalc() =>
model.set_candidate_grid(current_grid);
}
VolSurfaceColumn create_exp_column_view() {
var filter = new ComboCheckBox();
filter.SetResourceReference(FrameworkElement.StyleProperty, "ExpirationFilterDropDown");
@@ -115,7 +92,7 @@ namespace mbts.spark.VolSurface {
}
}
public event Action<IEnumerable<VolSurfaceDisplayGridExpiration>>? on_selection_changed;
public event Action<IEnumerable<VolSurfaceDisplayGridExpiration>> on_selection_changed;
public VolSurfaceDisplayGrid current_grid { get; private set; }
public VolSurfaceDisplayGrid committed_grid { get; private set; }
@@ -125,14 +102,14 @@ namespace mbts.spark.VolSurface {
public IReadOnlyObservableCollection<DIYGrid.ColumnBase> columns =>
_columns_model.views_with_header_ro;
public ObservableCollection<VolSurfaceRowVM> rows { get; } = new();
public ObservableCollection<VolSurfaceRowVM> visible_rows { get; } = new();
public ObservableSortedCollection<VolSurfaceRowVM> sorted_visible_rows { get; } = new(_row_comparer);
public ObservableCollection<VolSurfaceRowContext> rows { get; } = new();
public ObservableCollection<VolSurfaceRowContext> visible_rows { get; } = new();
public ObservableSortedCollection<VolSurfaceRowContext> sorted_visible_rows { get; } = new(_row_comparer);
public bool any_masters_selected =>
selected_rows.select_display_exp().where_master().Any();
public IEnumerable<VolSurfaceRowVM> selected_rows =>
public IEnumerable<VolSurfaceRowContext> selected_rows =>
visible_rows.where_selected();
public IEnumerable<DIYGridSuperHeaderVM> super_headers =>
@@ -141,14 +118,13 @@ namespace mbts.spark.VolSurface {
.Select(group => new DIYGridSuperHeaderVM(group.Key, group.Count(), collapsed_content: _short_header(group.Key)))
.ToList();
public ICommand populate_empty_exps_cmd => _parent.populate_empty_exps_cmd;
public ICommand main_settings_cmd => _parent.main_settings_cmd;
public ICommand advanced_settings_cmd => _parent.advanced_settings_cmd;
public ICommand graph_settings_cmd => _parent.vol_curve_vm.settings_command;
public ICommand grid_settings_cmd => _parent.grid_settings_cmd;
public ICommand main_settings_command => _parent.main_settings_command;
public ICommand advanced_settings_command => _parent.advanced_settings_command;
public ICommand graph_settings_command => _parent.vol_curve_vm.settings_command;
public ICommand grid_settings_command => _parent.grid_settings_command;
static IComparer<VolSurfaceRowVM> _row_comparer =>
Comparer<VolSurfaceDisplayGridExpiration>.Default.wrap<VolSurfaceDisplayGridExpiration, VolSurfaceRowVM>(r => r.expiration);
static IComparer<VolSurfaceRowContext> _row_comparer =>
Comparer<VolSurfaceDisplayGridExpiration>.Default.wrap<VolSurfaceDisplayGridExpiration, VolSurfaceRowContext>(r => r.expiration);
public void load_from(VolSurfaceMacroGridSettings grid_settings) {
_hidden_columns = new HashSet<string>(grid_settings.hidden_cols());
@@ -165,14 +141,13 @@ namespace mbts.spark.VolSurface {
rows.select_exp().Except(visible_rows.select_exp());
public void invalidate_rows() =>
_invalidate_rows.Invoke();
_invalidate_rows.execute();
public IDisposable defer_invalidate_rows() =>
_invalidate_rows.defer();
_invalidate_rows.defer_execution();
public VolSurfaceColumn get_column(string id) =>
columns.FirstOrDefault(c => c.id == id) as VolSurfaceColumn ??
throw new InvalidOperationException($"Failed to find column '{id}'");
columns.FirstOrDefault(c => c.id == id) as VolSurfaceColumn;
internal void signal_selection_changed() {
var e = on_selection_changed;
@@ -218,23 +193,23 @@ namespace mbts.spark.VolSurface {
}
}
internal void copy_to_selection(
VolSurfaceDisplayGridExpiration exp,
VolSurfaceDisplayGridColumn column,
GridColumnSet set) =>
_replicate(exp, selected_rows.select_display_exp().Except(exp), _get_columns(column, set));
internal void copy_to_selection(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
_replicate(exp, selected_rows.select_display_exp().Except(exp), _get_columns(column, set));
}
}
internal void copy_to_masters(
VolSurfaceDisplayGridExpiration exp,
VolSurfaceDisplayGridColumn column,
GridColumnSet set) =>
_replicate(exp, _expirations.where_master().Except(exp), _get_columns(column, set));
internal void copy_to_masters(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
_replicate(exp, _expirations.where_master().Except(exp), _get_columns(column, set));
}
}
internal void copy_to_all(
VolSurfaceDisplayGridExpiration exp,
VolSurfaceDisplayGridColumn column,
GridColumnSet set) =>
_replicate(exp, _expirations.Except(exp), _get_columns(column, set));
internal void copy_to_all(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
_replicate(exp, _expirations.Except(exp), _get_columns(column, set));
}
}
static string _short_header(string header) =>
string.Join("", header.Where(Char.IsUpper));
@@ -243,7 +218,7 @@ namespace mbts.spark.VolSurface {
!_hidden_columns.Contains(column.unique_col_name);
void _on_grid_updated() {
using var _ = _invalidate_rows.defer();
using var _ = _invalidate_rows.defer_execution();
var grid_new = model.get_active_grid();
// add/remove columns
var cols_new = grid_new.get_ordered_columns()
@@ -268,7 +243,7 @@ namespace mbts.spark.VolSurface {
}
current_grid = grid_new;
committed_grid = is_dirty ? model.get_committed_grid() : current_grid;
_invalidate_rows.Invoke();
_invalidate_rows.execute();
}
void _launch_shift_editor(VolSurfaceDisplayGridColumn column, Action<double> commit_shift) {
@@ -324,7 +299,7 @@ namespace mbts.spark.VolSurface {
VolSurfaceDisplayGridExpiration source,
IEnumerable<VolSurfaceDisplayGridExpiration> target_exps,
IEnumerable<VolSurfaceDisplayGridColumn> cols) {
foreach (var col in cols.Where(c => c.type.is_editable())) {
foreach (var col in cols) {
foreach (var exp in target_exps) {
_copy(source, exp, col);
}
@@ -332,14 +307,7 @@ namespace mbts.spark.VolSurface {
_commit();
}
void _copy(
VolSurfaceDisplayGridExpiration source,
VolSurfaceDisplayGridExpiration dest,
VolSurfaceDisplayGridColumn col
) {
if (!col.type.is_editable()) {
throw new ArgumentException("Expected col to be editable", nameof(col));
}
void _copy(VolSurfaceDisplayGridExpiration source, VolSurfaceDisplayGridExpiration dest, VolSurfaceDisplayGridColumn col) {
if (current_grid.read(source, col, out var value)) {
current_grid.set_grid_data(dest, col.unique_col_name, value);
}
@@ -349,7 +317,7 @@ namespace mbts.spark.VolSurface {
model.set_candidate_grid(current_grid);
class ColumnsModel : IDisposable {
IDisposable? _dispose;
IDisposable _dispose;
public ColumnsModel(VolSurfaceColumn row_header_col) {
views_with_header_ro = ObservableAutoWrapper.create_read_only_wrapper(views_with_header);
@@ -0,0 +1,335 @@
namespace mbts.spark.VolSurface {
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using mbts.ui.utility;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
using System.Windows.Media;
public struct VolSurfaceCellState {
public bool is_dirty => committed_text != null;
public FormattedText text;
public FormattedText committed_text;
}
class VolSurfaceRowContext : DisposableViewModelBase, ISelectable, IFormatCellsToClipboard, DIYGrid.IRowVM {
readonly VolSurfaceGridVM _parent;
readonly VolSurfaceDisplayGridExpiration _exp;
/// TODO: remove _text_cache when we are sure that the new row view
/// (<see cref="VolSurfaceRowView"/>) is solid. It must remain in place
/// until then, as it is used by old row view
/// (<see cref="VolSurfaceRowControl"/>).
readonly Dictionary<string, CellData> _cells = new();
MenuContext _context_menu;
bool _is_selected;
public VolSurfaceRowContext(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
_parent = parent;
_exp = exp;
_dispose = Disposable.Create(() => {
_cells.Values.DisposeAll();
_cells.Clear();
});
}
public event Action<bool> is_selected_changed;
public event Action invalidated;
public VolSurfaceDisplayGridExpiration expiration => _exp;
public bool is_selected {
get => _is_selected;
set {
if (_is_selected != value) {
_is_selected = value;
is_selected_changed?.Invoke(value);
_parent.signal_selection_changed();
}
}
}
public MenuContext context_menu =>
_context_menu ??= new(_parent, this);
public VolGridCellVM get_cell(VolSurfaceDisplayGridColumn column) {
if (!_cells.TryGetValue(column.unique_col_name, out var cell_data)) {
_cells.Add(column.unique_col_name, cell_data = _create_cell(column));
}
return cell_data.vm;
}
public void invalidate() {
foreach (var cell in _cells.Values) {
_sync_cell(cell.vm);
}
raise_invalidated();
}
public override string ToString() =>
_exp.ToString();
public string[] get_cell_clipboard_strings() =>
new[] { _exp.ToString() }.Concat(
_parent.columns.OfType<VolSurfaceColumn>()
.Skip(1)
.Select(c => {
var val = _parent.current_grid.read(_exp, c.model.unique_col_name);
return c.model.format(val);
}))
.ToArray();
public void raise_invalidated() =>
invalidated?.Invoke();
CellData _create_cell(VolSurfaceDisplayGridColumn column) {
var cell = column.type switch {
VolSurfaceColumnType.ReadWriteTick => create_tick_cell(),
_ => new VolGridCellVM(column.unique_col_name),
};
_sync_cell(cell);
var dispose = cell.observe_candidate().DistinctUntilChanged().OnDispatcher().Subscribe(value => {
var curr = _parent.current_grid.read(expiration, column);
if (Equals(value, curr)) {
return;
}
var grid = _parent.current_grid;
grid.write(expiration, column, value);
_parent.model.set_candidate_grid(grid);
});
return new(cell, dispose);
VolGridTickCellVM create_tick_cell() {
var cell = new VolGridTickCellVM(column.unique_col_name);
cell.request_tick += is_up => {
var col = _parent.get_column(column.unique_col_name);
if (col is null) {
throw new InvalidOperationException($"Failed to find column with id {column.unique_col_name}");
}
if (col.model?.tick_move is var tm) {
cell.candidate_value = tm(cell.candidate_value, is_up);
return;
}
throw new InvalidOperationException($"tick_move is not defined");
};
return cell;
}
}
void _sync_cell(VolGridCellVM cell) {
if (cell is null) {
return;
}
cell.committed_value = _parent.committed_grid.read(_exp, cell.column_id);
cell.candidate_value = _parent.current_grid.read(_exp, cell.column_id);
}
public class MenuContext : ViewModelBase {
readonly VolSurfaceRowContext _row;
readonly VolSurfaceGridVM _parent;
VolSurfaceColumn _col;
DIYGridSuperHeaderVM _supercol;
ICommand _revert_command;
ICommand _shift_selection_command;
ICommand _shift_masters_command;
ICommand _shift_all_command;
ICommand _clear_command;
ICommand _copy_to_selection_command;
ICommand _copy_to_masters_command;
ICommand _copy_to_all_command;
ICommand _copy_all_to_clipboard_command;
ICommand _smart_copy_rolls_rates_command;
ICommand _import_csv_command;
public MenuContext(
VolSurfaceGridVM parent,
VolSurfaceRowContext row) {
_parent = parent;
_row = row;
}
public string column_name => _col.model.display_name;
public string group_name => _supercol.id;
public string expiration_name => _row.ToString();
public VolSurfaceColumn column {
get => _col;
set => Set(ref _col, value);
}
public DIYGridSuperHeaderVM super_header {
get => _supercol;
set => Set(ref _supercol, value);
}
public VolSurfaceDisplayGridExpiration expiration => _row.expiration;
public class SymbolFilter {
readonly MenuContext _context;
bool? _visible;
public SymbolFilter(MenuContext context, string symbol, int count, int visible_count) {
_context = context;
this.symbol = symbol;
if (count == visible_count) {
_visible = true;
} else if (visible_count == 0) {
_visible = false;
} else {
_visible = null;
}
}
public string symbol { get; private set; }
public bool? visible {
get => _visible;
set {
_visible = value;
if (value == true) {
_context._show_symbol(symbol);
} else if (value == false) {
_context._hide_symbol(symbol);
}
}
}
}
public IEnumerable<SymbolFilter> symbols {
get {
var visible_exps = _parent.visible_rows
.Cast<VolSurfaceRowContext>()
.GroupBy(r => r._exp.symbol)
.ToDictionary(g => g.Key);
var result = _parent.rows
.GroupBy(r => r._exp.symbol)
.OrderBy(g => g.Key)
.Select(g => new SymbolFilter(this, g.Key, g.Count(), visible_exps.ContainsKey(g.Key) ? visible_exps[g.Key].Count() : 0));
return result;
}
}
public bool is_input_cell => _col.type == VolSurfaceColumnType.ReadWriteTick;
public ICommand main_settings_command => _parent.main_settings_command;
public ICommand advanced_settings_command => _parent.advanced_settings_command;
public ICommand grid_settings_command => _parent.grid_settings_command;
public ICommand graph_settings_command => _parent.graph_settings_command;
public ICommand revert_command =>
_revert_command ??= new DelegateCommand(_ => _row.get_cell(_col.model)?.revert());
public ICommand shift_selection_command =>
_shift_selection_command ??= new DelegateCommand(() => {
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_selection(_col.model);
}
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_masters_command =>
_shift_masters_command ??= new DelegateCommand(() => {
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_masters(_col.model);
}
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_all_command =>
_shift_all_command ??= new DelegateCommand(() => {
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_all(_col.model);
}
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
public ICommand clear_command =>
_clear_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.clear(_col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_to_selection_command =>
_copy_to_selection_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_selection(expiration, _col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_to_masters_command =>
_copy_to_masters_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_masters(expiration, _col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_to_all_command =>
_copy_to_all_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_all(expiration, _col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_all_to_clipboard_command =>
_copy_all_to_clipboard_command ??= new DelegateCommand(() => {
string clipboard_text = ClipboardHelper.GetExcelFormattedText(
_parent.visible_rows
.OfType<VolSurfaceRowContext>()
.Select(r => r.get_cell_clipboard_strings())
.Where(cells => cells != null));
if (!clipboard_text.is_null_or_empty()) {
ClipboardHelper.CopyTextToClipboard(clipboard_text);
}
});
public ICommand smart_copy_rolls_rates_command =>
_smart_copy_rolls_rates_command ??= new DelegateCommand(_ => _parent.model.sync_slave_ref_forwards(expiration.ToVSExp()));
public ICommand import_csv_command =>
_import_csv_command ??= FileDialogCommand.open_file(
_parent.model.import_csv_file,
() => _parent.model.csv_importing_enabled(),
null);
bool _has_editable_cells(string where) =>
!Enum.TryParse(where, out GridColumnSet gc) ||
gc == GridColumnSet.Column || _col.model.type != VolSurfaceColumnType.ReadOnly;
void _hide_symbol(string symbol) {
_parent.visible_rows.RemoveAll(s => ((VolSurfaceRowContext)s).expiration.symbol == symbol);
_parent.signal_selection_changed();
}
void _show_symbol(string symbol) {
// Insert items from rows to visible_Rows that have symbol=true in sorted order
// do this by making the desired collection and then leveraging sync_with
var visible = new HashSet<VolSurfaceDisplayGridExpiration>(_parent.visible_rows.Cast<VolSurfaceRowContext>().Select(row => row.expiration));
var desired = _parent.rows.Where(row => row.expiration.symbol == symbol || visible.Contains(row.expiration));
_parent.visible_rows.sync_with(desired);
}
}
class CellData : IDisposable {
IDisposable _dispose;
VolGridCellVM _vm;
public CellData(VolGridCellVM vm, IDisposable dispose) {
_vm = vm;
_dispose = dispose;
}
public VolGridCellVM vm => _vm;
public void Dispose() {
Disposable.dispose(ref _vm);
Disposable.dispose(ref _dispose);
}
}
}
}
@@ -1,220 +0,0 @@
#nullable enable
namespace mbts.spark {
using bts.collections;
using mbts.spark.VolSurface;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core.Disposables;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
class VolSurfaceRowContextMenuVM : DisposableViewModelBase {
readonly VolSurfaceRowVM _row;
readonly VolSurfaceGridVM _parent;
readonly Property<VolSurfaceColumn?> _column;
readonly Property<DIYGridSuperHeaderVM?> _super_header;
ICommand? _revert_cmd;
ICommand? _shift_selection_cmd;
ICommand? _shift_masters_cmd;
ICommand? _shift_all_cmd;
ICommand? _clear_cmd;
ICommand? _copy_to_selection_cmd;
ICommand? _copy_to_masters_cmd;
ICommand? _copy_to_all_cmd;
ICommand? _copy_all_to_clipboard_cmd;
ICommand? _smart_copy_rolls_rates_cmd;
ICommand? _import_csv_cmd;
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row) {
_parent = parent;
_row = row;
_column = backing<VolSurfaceColumn?>(nameof(column));
_super_header = backing<DIYGridSuperHeaderVM?>(nameof(super_header));
_dispose = Disposable.Create(
_column.invalidate_others_on_change(nameof(column_name)),
_super_header.invalidate_others_on_change(nameof(group_name)),
_parent.visible_rows.ObserveSelf()
.BufferLatest(TimeSpan.FromSeconds(1))
.OnDispatcher()
.Subscribe(_ => sync_symbols()));
void sync_symbols() {
var visible_exps = _parent.visible_rows.Map(r => r.expiration.symbol);
symbols.sync_with_models(
visible_exps,
kv => new SymbolItemVM(this, kv.Key),
(svm, kv) => {
svm.symbol = kv.Key;
svm.visible = SelectAllToggle.is_all_selected(
visible_exps[svm.symbol].Count(),
kv.Value.Count());
return svm;
});
}
}
public string column_name => column?.model?.display_name ?? string.Empty;
public string group_name => super_header?.id ?? string.Empty;
public string expiration_name => _row.ToString();
public VolSurfaceColumn? column {
get => _column.Value;
set => _column.set(value);
}
public DIYGridSuperHeaderVM? super_header {
get => _super_header.Value;
set => _super_header.set(value);
}
public VolSurfaceDisplayGridExpiration expiration => _row.expiration;
public ObservableCollection<SymbolItemVM> symbols { get; } = new();
public bool is_input_cell => column?.type == VolSurfaceColumnType.ReadWriteTick;
public ICommand populate_empty_exps_cmd => _parent.populate_empty_exps_cmd;
public ICommand main_settings_cmd => _parent.main_settings_cmd;
public ICommand advanced_settings_cmd => _parent.advanced_settings_cmd;
public ICommand grid_settings_cmd => _parent.grid_settings_cmd;
public ICommand graph_settings_cmd => _parent.graph_settings_cmd;
public ICommand revert_cmd =>
_revert_cmd ??= new Command(_ => {
_row.get_cell(_assert_model())?.revert();
});
public ICommand shift_selection_cmd =>
_shift_selection_cmd ??= new Command(() => {
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_selection(_assert_model());
}
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_masters_cmd =>
_shift_masters_cmd ??= new Command(() => {
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_masters(_assert_model());
}
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_all_cmd =>
_shift_all_cmd ??= new Command(() => {
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_all(_assert_model());
}
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
public ICommand clear_cmd =>
_clear_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.clear(_assert_model(), gc);
}
},
_has_editable_cells);
public ICommand copy_to_selection_cmd =>
_copy_to_selection_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_selection(expiration, _assert_model(), gc);
}
});
public ICommand copy_to_masters_cmd =>
_copy_to_masters_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_masters(expiration, _assert_model(), gc);
}
});
public ICommand copy_to_all_cmd =>
_copy_to_all_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_all(expiration, _assert_model(), gc);
}
});
public ICommand copy_all_to_clipboard_cmd =>
_copy_all_to_clipboard_cmd ??= new Command(() => {
string clipboard_text = ClipboardHelper.GetExcelFormattedText(
_parent.visible_rows
.OfType<VolSurfaceRowVM>()
.Select(r => r.get_cell_clipboard_strings())
.Where(cells => cells != null));
if (!clipboard_text.is_null_or_empty()) {
ClipboardHelper.CopyTextToClipboard(clipboard_text);
}
});
public ICommand smart_copy_rolls_rates_cmd =>
_smart_copy_rolls_rates_cmd ??= new Command(
() => _parent.model.sync_slave_ref_forwards(expiration.ToVSExp()));
public ICommand import_csv_cmd =>
_import_csv_cmd ??= FileDialogCommand.open_file(
_parent.model.import_csv_file,
_parent.model.csv_importing_enabled,
null);
VolSurfaceDisplayGridColumn _assert_model() =>
column?.model ?? throw new InvalidOperationException();
bool _has_editable_cells(string where) =>
!Enum.TryParse(where, out GridColumnSet gc) ||
gc == GridColumnSet.Column || _assert_model().type != VolSurfaceColumnType.ReadOnly;
void _hide_symbol(string symbol) {
_parent.visible_rows.RemoveAll(s => s.expiration.symbol == symbol);
_parent.signal_selection_changed();
}
void _show_symbol(string symbol) {
// Insert items from rows to visible_Rows that have symbol=true in sorted order
// do this by making the desired collection and then leveraging sync_with
var visible = _parent.visible_rows
.Select(row => row.expiration)
.ToHashSet();
var desired = _parent.rows.Where(
row => row.expiration.symbol == symbol || visible.Contains(row.expiration));
_parent.visible_rows.sync_with(desired);
}
public class SymbolItemVM : ViewModelBase {
readonly VolSurfaceRowContextMenuVM _context;
string _symbol;
bool? _visible;
public SymbolItemVM(
VolSurfaceRowContextMenuVM context, string symbol) {
_context = context;
_symbol = symbol;
}
public string symbol {
get => _symbol;
set => Set(ref _symbol, value);
}
public bool? visible {
get => _visible;
set {
if (Set(ref _visible, value)) {
if (value is true) {
_context._show_symbol(symbol);
} else if (value is false) {
_context._hide_symbol(symbol);
}
}
}
}
}
}
}
@@ -0,0 +1,372 @@
// using mbts;
// using mbts.ui;
// using mbts.ui.controls;
// using mbts.ui.dpi;
// using mbts.ui.utility.text;
// using System;
// using System.Collections.Generic;
// using System.Diagnostics;
// using System.Globalization;
// using System.Linq;
// using System.Text;
// using System.Threading.Tasks;
// using System.Windows;
// using System.Windows.Controls;
// using System.Windows.Input;
// using System.Windows.Media;
// namespace mbts.spark.VolSurface {
// class VolSurfaceRowControl : DIYGrid.HighPerformanceRow<VolSurfaceRowContext> {
// FormattedText _exp_text;
// readonly double _padding = 5.0;
// readonly Pen _dirty_pen = new Pen(Brushes.Red, 1.0);
// readonly Pen _selection_pen = new Pen(Brushes.Black, 1.0) { DashStyle = DashStyles.Dot };
// TickUpDown _cell_editor_backing;
// TickUpDown _cell_editor => _cell_editor_backing ??= new ();
// int? _selected_cell;
// public VolSurfaceRowControl() {
// Loaded += (s, e) => ContextMenu = TryFindResource("context_menu") as ContextMenu;
// GotKeyboardFocus += (s, e) => {
// if (e.OriginalSource is not FrameworkElement el) {
// return;
// }
// var cell_tl = el.TranslatePoint(new Point(0, 0), this);
// _on_focus_move(DIYGrid.RowUtils.column_at(_column_layout, cell_tl));
// };
// }
// int? _column_index(DIYGrid.ColumnGeometry col) =>
// _column_layout.TryGetFirst(c => c.Equals(col), out var _, out var idx) ? idx : null;
// //private static int _render_count = 0;
// protected override void OnRender(DrawingContext dc) {
// // Fill with transparent for hit testing
// dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, new Rect(0, 0, _column_layout.Sum(c => c.width), RenderSize.Height));
// string last_group = "";
// foreach (var cell in _column_layout) {
// // Render collapsed columns
// if (cell.column.is_collapsed) {
// dc.DrawRectangle(BTSColors.AW2.collapsed, null, new Rect(cell.left, 0, cell.width, Height));
// continue;
// }
// var column = (VolSurfaceSimplifiedColumn)cell.column;
// VolSurfaceCellState celldata;
// // Get the cell text
// if (column.type == VolSurfaceSimplifiedColumnType.RowHeader) {
// // Fill in this one
// dc.DrawRectangle(BTSColors.header, null, new Rect(cell.left, 0, cell.width, Height));
// var exp = _row.expiration;
// if (_exp_text == null) {
// _exp_text = format_text(exp.ToString(), exp.is_slave ? Brushes.LightGray : Brushes.White);
// }
// celldata = new VolSurfaceCellState() {
// text = _exp_text
// };
// } else if (column.type == VolSurfaceSimplifiedColumnType.ReadOnly) {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Blue), _ => null);
// } else {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Black), format(Brushes.DarkGray));
// }
// // If the cell is partly hidden clip the draw
// if (cell.is_partially_obscured) {
// dc.PushClip(new RectangleGeometry(
// new Rect(cell.left, 0, cell.width, Height)));
// }
// // draw text centered vertially
// double total_width = _padding + celldata.text.Width;
// double pad_top = (Height - celldata.text.Height) / 2.0;
// dc.DrawText(celldata.text, new Point(cell.unclipped_left + _padding, pad_top));
// if (celldata.committed_text != null) {
// pad_top = (Height - celldata.committed_text.Height) / 2.0;
// dc.DrawText(celldata.committed_text, new Point(cell.unclipped_left + total_width, pad_top));
// total_width += celldata.committed_text.Width;
// }
// // draw grid lines
// double line_width; Brush fill;
// if (last_group == cell.group) { line_width = 1; fill = _grid.VerticalGridLineBrush; } else { line_width = 2; fill = _grid.VerticalGroupSeparatorBrush; }
// dc.DrawRectangle(fill, null, new Rect(cell.left - line_width, 0, line_width, Height));
// Rect cell_border_rect = new Rect(cell.unclipped_left + 1, 0, Math.Max(0, cell.width - (line_width * 2)), Height - 1);
// // draw dirty rect
// if (celldata.is_dirty) {
// dc.DrawRectangle(null, _dirty_pen, cell_border_rect);
// }
// // Draw selection
// if (_selected_cell == _column_index(cell) && column.type != VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// dc.DrawRectangle(null, _selection_pen, cell_border_rect);
// }
// if (cell.is_partially_obscured) { dc.Pop(); }
// total_width += _padding;//right padding
// if (!celldata.is_dirty && column.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) total_width += 22; // size of buttons on a tickupdown
// if (total_width > cell.width) {
// Dispatcher.BeginInvoke(((Action)(() => cell.column.Width = total_width)));
// }
// last_group = cell.group;
// }
// if (_selected_cell != NO_CELL) {
// if (_cell_editor.Visibility == Visibility.Visible) {
// var position = _column_geometry[_selected_cell];
// PositionControlOver(tud, position);
// }
// }
// //++_render_count;
// //dc.DrawText(
// // format_text(_render_count.ToString(), Brushes.Black),
// // new Point(0, 0));
// }
// Func<string, FormattedText> format(Brush brush) =>
// str => format_text(str, brush);
// void _on_focus_move(DIYGrid.ColumnGeometry? new_column) {
// if (new_column != null) {
// enable_edit(new_column.Value);
// }
// InvalidateVisual();
// }
// private async void enable_edit(DIYGrid.ColumnGeometry column) {
// await Task.Yield();
// var col = (VolSurfaceSimplifiedColumn)column.column;
// var tud = _grid.get_edit_control<TickUpDown>();
// if (col.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// tud.DataContext = _row.get_edit_context(col.volsurface_column);
// PositionControlOver(tud, column);
// var fe = tud.Content as TextBox;
// if (fe != null) {
// await Task.Yield();
// fe.Focus();
// fe.SelectAll();
// }
// } else {
// tud.DataContext = null;
// tud.Visibility = Visibility.Collapsed;
// var item = this.find_ancestor_of_type<ListBoxItem>();
// if (item != null) {
// item.Focus();
// }
// }
// }
// protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) {
// // _grid.column
// var cell = DIYGrid.RowUtils.column_at(_column_layout, e.GetPosition(this));
// if (ContextMenu != null) {
// if (cell.HasValue && DIYGrid.RowUtils.column_index(_column_layout, cell.Value) > (_grid.FrozenColumnCount - 1)) {
// ContextMenu.DataContext = _row.get_context_menu_context((VolSurfaceSimplifiedColumn)cell.Value.column, cell.Value.super_column);
// } else {
// e.Handled = true;
// ContextMenu.DataContext = null;
// }
// }
// base.OnMouseRightButtonDown(e);
// }
// FormattedText format_text(string content, Brush fg) {
// var ft = new FormattedText(content, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
// TextUtils.StandardTypeface, FontSizes.Regular, Brushes.Black, HighDpiExtensions.dpi_ratio);
// return ft;
// }
// }
// }
// using mbts;
// using mbts.ui;
// using mbts.ui.controls;
// using mbts.ui.dpi;
// using mbts.ui.utility.text;
// using System;
// using System.Collections.Generic;
// using System.Diagnostics;
// using System.Globalization;
// using System.Linq;
// using System.Text;
// using System.Threading.Tasks;
// using System.Windows;
// using System.Windows.Controls;
// using System.Windows.Input;
// using System.Windows.Media;
// namespace mbts.spark.VolSurface {
// class VolSurfaceRowControl : DIYGrid.RowBase {
// VolSurfaceRowContext _row;
// FormattedText _exp_text;
// readonly double _padding = 5.0;
// readonly Pen _dirty_pen = new Pen(Brushes.Red, 1.0);
// readonly Pen _selection_pen = new Pen(Brushes.Black, 1.0) { DashStyle = DashStyles.Dot };
// public VolSurfaceRowControl() {
// DataContextChanged += OnDataContextChanged;
// Loaded += OnLoaded;
// }
// #region SelectedCell
// public static readonly DependencyProperty SelectedCellProperty =
// WPFHelper.create_dp<object, VolSurfaceRowControl>(nameof(SelectedCell));
// public object SelectedCell {
// get => GetValue(SelectedCellProperty);
// set => SetValue(SelectedCellProperty, value);
// }
// #endregion
// void OnLoaded(object sender, RoutedEventArgs e) {
// ContextMenu = TryFindResource("context_menu") as ContextMenu;
// }
// void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) {
// var oldrow = e.OldValue as VolSurfaceRowContext;
// if (oldrow != null) {
// oldrow.on_invalidate -= InvalidateVisual;
// }
// _row = DataContext as VolSurfaceRowContext;
// _row.on_invalidate += InvalidateVisual;
// }
// //private static int _render_count = 0;
// protected override void OnRender(DrawingContext dc) {
// if (_grid == null) return;
// // Fill with transparent for hit testing
// dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, new Rect(0, 0, _column_geometry.Sum(g => g.width), RenderSize.Height));
// string last_group = "";
// foreach (var cell in _column_geometry) {
// // Render collapsed columns
// if (cell.column.is_collapsed) {
// dc.DrawRectangle(BTSColors.AW2.collapsed, null, new Rect(cell.left, 0, cell.width, Height));
// continue;
// }
// var column = (VolSurfaceSimplifiedColumn)cell.column;
// VolSurfaceCellState celldata;
// // Get the cell text
// if (column.type == VolSurfaceSimplifiedColumnType.RowHeader) {
// // Fill in this one
// dc.DrawRectangle(BTSColors.header, null, new Rect(cell.left, 0, cell.width, Height));
// var exp = _row.expiration;
// if (_exp_text == null) {
// _exp_text = format_text(exp.ToString(), exp.is_slave ? Brushes.LightGray : Brushes.White);
// }
// celldata = new VolSurfaceCellState() { text = _exp_text };
// } else if (column.type == VolSurfaceSimplifiedColumnType.ReadOnly) {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Blue), _ => null);
// } else {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Black), format(Brushes.DarkGray));
// }
// // If the cell is partly hidden clip the draw
// if (cell.is_partially_obscured) {
// dc.PushClip(new RectangleGeometry(
// new Rect(cell.left, 0, cell.width, Height)));
// }
// // draw text centered vertially
// double total_width = _padding + celldata.text.Width;
// double pad_top = (Height - celldata.text.Height) / 2.0;
// dc.DrawText(celldata.text, new Point(cell.unclipped_left + _padding, pad_top));
// if (celldata.committed_text != null) {
// pad_top = (Height - celldata.committed_text.Height) / 2.0;
// dc.DrawText(celldata.committed_text, new Point(cell.unclipped_left + total_width, pad_top));
// total_width += celldata.committed_text.Width;
// }
// // draw grid lines
// double line_width; Brush fill;
// if (last_group == cell.group) { line_width = 1; fill = _grid.VerticalGridLineBrush; } else { line_width = 2; fill = _grid.VerticalGroupSeparatorBrush; }
// dc.DrawRectangle(fill, null, new Rect(cell.left - line_width, 0, line_width, Height));
// Rect cell_border_rect = new Rect(cell.unclipped_left + 1, 0, Math.Max(0, cell.width - (line_width * 2)), Height - 1);
// // draw dirty rect
// if (celldata.is_dirty) {
// dc.DrawRectangle(null, _dirty_pen, cell_border_rect);
// }
// // Draw selection
// if (_selected_cell == column_index(cell) && column.type != VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// dc.DrawRectangle(null, _selection_pen, cell_border_rect);
// }
// if (cell.is_partially_obscured) { dc.Pop(); }
// total_width += _padding;//right padding
// if (!celldata.is_dirty && column.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) total_width += 22; // size of buttons on a tickupdown
// if (total_width > cell.width) {
// Dispatcher.BeginInvoke(((Action)(() => cell.column.Width = total_width)));
// }
// last_group = cell.group;
// }
// //++_render_count;
// //dc.DrawText(
// // format_text(_render_count.ToString(), Brushes.Black),
// // new Point(0, 0));
// }
// private Func<string, FormattedText> format(Brush brush) {
// return str => format_text(str, brush);
// }
// protected override void OnClick(DIYGrid.ColumnGeometry column) {
// }
// protected override void OnFocusMove(DIYGrid.ColumnGeometry? new_column) {
// if (new_column != null) enable_edit(new_column.Value);
// InvalidateVisual();
// }
// private async void enable_edit(DIYGrid.ColumnGeometry column) {
// await Task.Yield();
// var col = (VolSurfaceSimplifiedColumn)column.column;
// var tud = _grid.get_edit_control<TickUpDown>();
// if (col.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// tud.DataContext = _row.get_edit_context(col.volsurface_column);
// PositionControlOver(tud, column);
// var fe = tud.Content as TextBox;
// if (fe != null) {
// await Task.Yield();
// fe.Focus();
// fe.SelectAll();
// }
// } else {
// tud.DataContext = null;
// tud.Visibility = Visibility.Collapsed;
// var item = this.find_ancestor_of_type<ListBoxItem>();
// if (item != null) {
// item.Focus();
// }
// }
// }
// protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) {
// var cell = column_at(e.GetPosition(this));
// if (ContextMenu != null) {
// if (cell.HasValue && column_index(cell.Value) > (_grid.FrozenColumnCount - 1)) {
// ContextMenu.DataContext = _row.get_context_menu_context((VolSurfaceSimplifiedColumn)cell.Value.column, cell.Value.super_column);
// } else {
// e.Handled = true;
// ContextMenu.DataContext = null;
// }
// }
// base.OnMouseRightButtonDown(e);
// }
// FormattedText format_text(string content, Brush fg) {
// var ft = new FormattedText(content, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
// TextUtils.StandardTypeface, FontSizes.Regular, Brushes.Black, HighDpiExtensions.dpi_ratio);
// return ft;
// }
// }
// }
@@ -1,149 +0,0 @@
#nullable enable
namespace mbts.spark.VolSurface {
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using Spark.Core;
using Spark.Core.Disposables;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
class VolSurfaceRowVM : DisposableViewModelBase, ISelectable, IFormatCellsToClipboard, DIYGrid.IRowVM {
readonly VolSurfaceGridVM _parent;
readonly VolSurfaceDisplayGridExpiration _exp;
readonly Dictionary<string, CellData> _cells = new();
readonly DeferrableAction _request_calculate;
VolSurfaceRowContextMenuVM? _context_menu;
bool _is_selected;
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
_parent = parent;
_exp = exp;
_request_calculate = new(() => request_calculate?.Invoke());
_dispose = Disposable.Create(() => {
_cells.Values.DisposeAll();
_cells.Clear();
_context_menu?.Dispose();
});
}
public event Action<bool>? is_selected_changed;
public event Action? invalidated;
public event Action? request_calculate;
public VolSurfaceDisplayGridExpiration expiration => _exp;
public bool is_selected {
get => _is_selected;
set {
if (Set(ref _is_selected, value)) {
is_selected_changed?.Invoke(value);
_parent.signal_selection_changed();
}
}
}
public VolSurfaceRowContextMenuVM context_menu =>
_context_menu ??= new(_parent, this);
public VolSurfaceCellVM get_cell(VolSurfaceDisplayGridColumn column) =>
_cells.GetOrAdd(column.unique_col_name, _ => _create_cell(column)).vm;
public void invalidate() {
using (_request_calculate.supress()) {
foreach (var cell in _cells.Values) {
_sync_cell(cell.vm);
}
}
invalidated?.Invoke();
}
public string[] get_cell_clipboard_strings() =>
new[] { _exp.ToString() }.Concat(
_parent.columns.OfType<VolSurfaceColumn>().Skip(1).Select(c => {
var val = _parent.current_grid.read(_exp, c.model.unique_col_name);
return c.model.format(val);
}))
.ToArray();
public override string ToString() =>
_exp.ToString();
void DIYGrid.IRowVM.raise_invalidated() =>
invalidated?.Invoke();
CellData _create_cell(VolSurfaceDisplayGridColumn column) {
var cell = column.type switch {
VolSurfaceColumnType.ReadWriteTick => create_tick_cell(),
_ => new VolSurfaceCellVM(_exp, column)
};
_sync_cell(cell);
return new(cell, _connect_cell(cell));
VolSurfaceCellVM create_tick_cell() {
var cell = new VolSurfaceTickCellVM(_exp, column);
cell.request_tick += is_up => {
var col = _parent.get_column(column.unique_col_name);
if (col.model?.tick_move is var tm) {
cell.candidate_value = tm?.Invoke(cell.candidate_value, is_up);
return;
}
throw new InvalidOperationException($"tick_move is not defined");
};
return cell;
}
}
void _sync_cell(VolSurfaceCellVM cell) {
if (cell is null) {
return;
}
using var _ = _request_calculate.supress();
cell.reset(
committed_value: _parent.committed_grid.read(_exp, cell.column_id),
candidate_value: _parent.current_grid.read(_exp, cell.column_id));
}
IDisposable? _connect_cell(VolSurfaceCellVM cell) {
return cell.column.type switch {
VolSurfaceColumnType.ReadWriteTick => connect_input(),
_ => null
};
IDisposable connect_input() {
cell.candidate_value_changed += on_candidate_value_changed;
return Disposable.Create(() =>
cell.candidate_value_changed -= on_candidate_value_changed);
void on_candidate_value_changed(object? oldval, object? newval) {
var curr = _parent.current_grid.read(expiration, cell.column);
if (cell.column.comparer.Equals(newval, curr)) {
return;
}
var grid = _parent.current_grid;
grid.write(expiration, cell.column, newval);
_request_calculate.Invoke();
}
}
}
class CellData : IDisposable {
IDisposable? _dispose;
public CellData(VolSurfaceCellVM vm, IDisposable? dispose) {
this.vm = vm;
_dispose = Disposable.Create(vm, dispose);
}
public VolSurfaceCellVM vm { get; }
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
}
@@ -1,27 +0,0 @@
#nullable enable
namespace mbts.spark {
using mbts.ui;
using mbts.ui.controls;
using System;
using System.Windows.Input;
class VolSurfaceTickCellVM : VolSurfaceCellVM {
ICommand? _tick_up_cmd;
ICommand? _tick_down_cmd;
public VolSurfaceTickCellVM(
VolSurfaceDisplayGridExpiration expiration, VolSurfaceDisplayGridColumn column)
: base(expiration, column) { }
public event Action<bool>? request_tick;
public ICommand tick_up_cmd =>
_tick_up_cmd ??= new DelegateCommand(() =>
request_tick?.Invoke(true));
public ICommand tick_down_cmd =>
_tick_down_cmd ??= new DelegateCommand(() =>
request_tick?.Invoke(false));
}
}
@@ -3,8 +3,6 @@ using mbts.ui;
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -23,7 +21,7 @@ namespace mbts.spark {
if (_settings.precomputed_theo_handles == null)
_settings.precomputed_theo_handles = new List<double>();
vol_surface_name = vs_name;
this.commit = new DelegateCommand(() => request_commit?.Invoke(ProtobufSerializationHelper.clone(_settings)));
this.commit = new DelegateCommand(() => request_commit?.Invoke(ProtoBufSerializationHelper.clone_protobuf(_settings)));
}
public event Action<VolSurfaceAdvancedSettings> request_commit;
@@ -96,7 +96,7 @@ namespace mbts.spark {
get => _core_settings.font_weight_override;
set {
using var _ = detect_property_change();
_core_settings.with(font_weight_override: value.HasValue ? new(value) : null);
_core_settings.with(font_weight_override: value.HasValue ? new NullableFontWeightProto(value) : null);
}
}
@@ -0,0 +1,72 @@
using mbts.ui;
using mbts.ui.controls.graph;
using System;
using System.Windows.Input;
using System.Windows.Media;
namespace mbts.spark
{
class VolSurfaceGraphSettingsEditorVM
{
public VolSurfaceGraphSettingsEditorVM(string vol_surface_name, VolSurfaceGraphSettings settings, Action<VolSurfaceGraphSettings> commit) {
this.vol_surface_name = vol_surface_name;
_settings = settings;
this.commit = new DelegateCommand(() => commit(_settings));
}
private readonly VolSurfaceGraphSettings _settings;
public string vol_surface_name { get; private set; }
public VolSurfaceScatterSeriesSettingsVM implied_puts { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.implied_puts); } }
public VolSurfaceScatterSeriesSettingsVM implied_atm { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.implied_atm); } }
public VolSurfaceScatterSeriesSettingsVM implied_calls { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.implied_calls); } }
public VolSurfaceScatterSeriesSettingsVM put_control_points { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.put_control_points); } }
public VolSurfaceScatterSeriesSettingsVM atm { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.atm); } }
public VolSurfaceScatterSeriesSettingsVM call_control_points { get { return new VolSurfaceScatterSeriesSettingsVM(_settings.call_control_points); } }
public VolSurfaceLineSeriesSettingsVM put_wing { get { return new VolSurfaceLineSeriesSettingsVM(_settings.put_wing); } }
public VolSurfaceLineSeriesSettingsVM inner_curve { get { return new VolSurfaceLineSeriesSettingsVM(_settings.inner_curve); } }
public VolSurfaceLineSeriesSettingsVM call_wing { get { return new VolSurfaceLineSeriesSettingsVM(_settings.call_wing); } }
public VolSurfaceLineSeriesSettingsVM vol_path { get { return new VolSurfaceLineSeriesSettingsVM(_settings.vol_path); } }
public ICommand commit { get; private set; }
}
class VolSurfaceScatterSeriesSettingsVM
{
public VolSurfaceScatterSeriesSettingsVM(ScatterSeriesSettings settings) {
_settings = settings;
}
private readonly ScatterSeriesSettings _settings;
public MarkerShape shape { get { return _settings.shape; } set { _settings.shape = value; } }
public double size { get { return _settings.size; } set { _settings.size = value; } }
public Color fill {
get => _settings.fill;
set => _settings.fill = value;
}
public Color stroke {
get => _settings.stroke;
set => _settings.stroke = value;
}
public Array shapes { get { return Enum.GetValues(typeof(MarkerShape)); } }
}
class VolSurfaceLineSeriesSettingsVM
{
public VolSurfaceLineSeriesSettingsVM(LineSeriesSettings settings) {
_settings = settings;
}
private readonly LineSeriesSettings _settings;
public Color color { get { return (Color)_settings.color; } set { _settings.color = (BTSColor)value; } }
public double thickness { get { return _settings.stroke_thickness; } set { _settings.stroke_thickness = value; } }
}
}
@@ -9,9 +9,6 @@ namespace mbts.spark {
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core.Disposables;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -26,9 +23,6 @@ namespace mbts.spark {
readonly VolSurfaceSettings _settings;
readonly VolSurfaceCoreSettings _core_settings;
string _selected_section;
bool _can_edit_name = true;
public VolSurfaceSettingsEditorVM(IBus bus, VolSurfaceSettings settings, Action<VolSurfaceSettings> commit) {
if (settings is null) {
throw new ArgumentNullException(nameof(settings));
@@ -119,23 +113,7 @@ namespace mbts.spark {
}
}
public string vol_surface_name {
get => _core_settings.vol_surface_name;
set {
using var _ = detect_property_change();
_core_settings.vol_surface_name = value;
}
}
public bool can_edit_name {
get => _can_edit_name;
set => Set(ref _can_edit_name, value);
}
public string selected_section {
get => _selected_section;
set => Set(ref _selected_section, value);
}
public string vol_surface_name { get { return _core_settings.vol_surface_name; } }
public VSSymbolStructureVM symbol_structure_vm { get; set; }
public VolModelPolynomialVM vol_model_polynomial_vm { get; } = new();
@@ -375,7 +353,7 @@ namespace mbts.spark {
public ICommand commit { get; }
public VolSurfaceSettings get_settings() {
var rv = ProtobufSerializationHelper.clone(_settings);
var rv = ProtoBufSerializationHelper.clone_protobuf(_settings);
var symbols = symbol_structure_vm.driver_grids
.SelectMany(dg => dg.symbols.Where(sym => sym.is_selected))
.ToList();
@@ -540,22 +518,17 @@ namespace mbts.spark {
public ObservableCollection<VSSymbol> symbols { get; private set; }
public void Dispose() =>
symbols.DisposeAll(true);
Disposable.dispose(symbols);
}
public class VSSymbolStructureVM : DisposableViewModelBase {
readonly Property<VSSymbolGridVM> _selected_driver_grid;
public VSSymbolStructureVM(IBus bus, VolSurfaceSettings settings) {
driver_grids = new ObservableCollection<VSSymbolGridVM>();
_selected_driver_grid = backing<VSSymbolGridVM>(nameof(selected_driver_grid));
settings.core_settings.master_slave_relationships ??= new List<VolSurfaceSymbolRelationship>();
settings.core_settings.implied_vol_marketdata_relationships ??= new List<VolSurfaceSymbolRelationship>();
_dispose = Disposable.Create(
driver_grids.Subscribe((s, e) =>
selected_driver_grid ??= driver_grids.FirstOrDefault()),
bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(on_exp_params_input),
Disposable.Create(() => driver_grids.DisposeAll(true)));
_dispose = new DisposableCombo(
bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(on_exp_params_input)) +
new Action(() => Disposable.dispose(driver_grids));
void on_exp_params_input(AnalyticsExpirationParametersMap data) {
var driver_map = data.get_option_driver_map();
@@ -613,10 +586,6 @@ namespace mbts.spark {
public IReadOnlyList<VolSurfaceEnums.VolSurfacePricingModel> pricing_models => EnumHelper.get_values<VolSurfaceEnums.VolSurfacePricingModel>();
public ObservableCollection<VSSymbolGridVM> driver_grids { get; private set; }
public VSSymbolGridVM selected_driver_grid {
get => _selected_driver_grid.Value;
set => _selected_driver_grid.set(value);
}
}
public class RotationVM : ViewModelBase, IEquatable<RotationVM> {
@@ -1,15 +1,14 @@
namespace mbts.spark {
using bts;
using bts.utils;
using mbts.ui;
using mbts.ui.shell;
using Spark.Core.Reflection;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
class VolSurfaceMacroActionsVM : ViewModelBase {
readonly VolSurfaceDisplayModel _model;
@@ -77,8 +76,8 @@
public IRaiseCanExecuteChangedCommand vol_shift { get; }
IEnumerable<IRaiseCanExecuteChangedCommand> _commands =>
ReflectionHelper.property_getters<VolSurfaceMacroActionsVM, IRaiseCanExecuteChangedCommand>()
.Select(pg => pg.get(this));
ObjectSnapshot.property_delegates_of_type<VolSurfaceMacroActionsVM, IRaiseCanExecuteChangedCommand>()
.Select(g => g(this));
public void selection_changed(IEnumerable<VolSurfaceDisplayGridExpiration> selected) {
_selected_exps = selected.ToList();
@@ -7,8 +7,6 @@
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+93 -129
View File
@@ -1,5 +1,5 @@
#nullable enable
namespace mbts.spark {
using bts;
using bts.api;
using bts.collections;
@@ -8,107 +8,48 @@ namespace mbts.spark {
using mbts.spark.VolSurface;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.settings;
using mbts.ui.shell;
using Spark.Core.Disposables;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
class VolSurfaceVM : DisposableViewModelBase {
class VolSurfaceVM : ViewModelBase, IDisposable {
readonly int _vs_id;
readonly IBus _bus;
readonly string _request_id = Guid.NewGuid().ToString();
readonly VolSurfaceDisplayModel _model;
readonly IRaiseCanExecuteChangedCommand _revert_cmd;
readonly IRaiseCanExecuteChangedCommand _commit_cmd;
readonly IDialogCommand _main_settings_cmd;
readonly IDialogCommand _advanced_settings_cmd;
readonly IDialogCommand _grid_settings_cmd;
string? _selected_state = string.Empty;
VolSurfaceDisplayModel _model;
VolSurfaceMacroGridSettings _grid_settings;
bool _ignore_implied_vol_settings;
public VolSurfaceVM(
VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
public VolSurfaceVM(VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
Log.notnull(startup_data);
_model = model;
var demux = new VolSurfaceEventDemux(model);
_vs_id = id;
_bus = bus;
macro_actions = new VolSurfaceMacroActionsVM(_model);
globals = new VolSurfaceGlobalParameterVM(_model);
// grid
_grid_settings = startup_data.macro_grid_settings ?? new VolSurfaceMacroGridSettings();
var hidden_exps_set = startup_data.hidden_exps.empty_if_null().ToHashSet();
grid = new VolSurfaceGridVM(
this, _model, _grid_settings.hidden_cols(), hidden_exps_set);
grid.on_selection_changed += _on_grid_selection_changed;
_model.publish_grid_settings(_grid_settings);
// graphs
var demux = new VolSurfaceEventDemux(model);
vol_curve_vm = new VolSurfaceGraphVM(
_model, demux, startup_data, (show_ivol, exp) =>
_model.publish_new_grid_selection(_request_id, exp, show_ivol));
_model, demux, startup_data, (show_ivol, exp) => _model.publish_new_grid_selection(_request_id, exp, show_ivol));
vol_terms_vm = new VolTermsGraphVM(_model, demux);
// command
populate_empty_exps_cmd = new Command(() => { _model.populate_empty_expirations(); });
_revert_cmd = new Command(o => _model.revert(), o => _model.is_dirty);
_commit_cmd = new Command(o => _model.commit(), o => _model.is_dirty);
load_previous_cmd = new Command(
load_previous, () => !selected_previous_state.is_null_or_empty());
_main_settings_cmd = new DialogCommand(mk_main_settings_win);
_advanced_settings_cmd = new DialogCommand(mk_advanced_settings_win);
_grid_settings_cmd = new DialogCommand(mk_grid_settings_win);
_model.on_dirty_change += () => {
RaisePropertyChanged(nameof(is_dirty));
_revert_cmd.RaiseCanExecuteChanged();
_commit_cmd.RaiseCanExecuteChanged();
};
demux.on_candidate_grid_change += () =>
previous_states.sync_with(_model.get_previous_states());
demux.on_schema_change += () => {
var existing_cols = _grid_settings.column_settings.ToDictionary(c => c.id);
_grid_settings.set_columns(
model.get_active_grid()
.get_ordered_columns()
.Select(col => existing_cols.GetValueOrDefault(col.unique_col_name) ??
VolSurfaceColumnSettings.from_column_model(col)));
};
_dispose = Disposable.Create(
vol_curve_vm,
vol_terms_vm,
globals,
Disposable.Create(() => grid?.Dispose()),
_main_settings_cmd,
_advanced_settings_cmd,
_grid_settings_cmd,
_model);
Window? mk_main_settings_win() {
revert_command = new DelegateCommand(o => _model.revert(), o => _model.is_dirty);
commit_command = new DelegateCommand(o => _model.commit(), o => _model.is_dirty);
load_previous_command = new DelegateCommand(_ => { var cur = selected_previous_state; selected_previous_state = null; _model.load_previous_state(cur); }, _ => !string.IsNullOrEmpty(selected_previous_state));
main_settings_command = new DialogCommand(() => {
var settings = _model.get_active_settings();
if (settings is null) {
if (settings == null) {
return null;
}
return new VolSurfaceSettingsEditor {
DataContext = new VolSurfaceSettingsEditorVM(
_bus, settings, _model.set_candidate_settings) {
can_edit_name = false
}
};
}
Window? mk_advanced_settings_win() {
return new VolSurfaceSettingsEditor { DataContext = new VolSurfaceSettingsEditorVM(_bus, settings, _model.set_candidate_settings) };
});
advanced_settings_command = new DialogCommand(() => {
var settings = _model.get_active_settings();
if (settings == null) {
return null;
@@ -128,72 +69,76 @@ namespace mbts.spark {
// )
// };
return null;
}
Window? mk_grid_settings_win() {
});
grid_settings_command = new DialogCommand(() => {
var settings = _model.get_active_settings();
if (settings is null) {
if (settings == null) {
return null;
}
var vm = new VolSurfaceGridSettingsEditorVM(
settings.core_settings.vol_surface_name, _grid_settings.Clone());
var vm = new VolSurfaceGridSettingsEditorVM(settings.core_settings.vol_surface_name, _grid_settings.Clone());
vm.request_commit += on_grid_settings;
return new VolSurfaceGridSettingsEditor {
DataContext = vm
};
});
_model.on_dirty_change += raise_dirty_changed;
macro_actions = new VolSurfaceMacroActionsVM(_model);
globals = new VolSurfaceGlobalParameterVM(_model);
demux.on_candidate_grid_change += () => previous_states.sync_with(_model.get_previous_states());
demux.on_schema_change += () => {
// _grid_settings.clear_columns();
var existing_cols = _grid_settings.column_settings.ToDictionary(c => c.id);
_grid_settings.set_columns(
model.get_active_grid()
.get_ordered_columns()
.Select(col => {
if (!existing_cols.TryGetValue(col.unique_col_name, out var rv)) {
rv = VolSurfaceColumnSettings.from_column_model(col);
}
return rv;
}));
};
grid = new VolSurfaceGridVM(this, _model, _grid_settings.hidden_cols(), new HashSet<VolSurfaceExpiration>(startup_data.hidden_exps ?? Enumerable.Empty<VolSurfaceExpiration>()));
grid.on_selection_changed += _on_grid_selection_changed;
void on_grid_settings(VolSurfaceMacroGridSettings new_settings) {
using var _ = grid.defer_invalidate_rows();
_grid_settings = new_settings;
grid.load_from(_grid_settings);
grid.invalidate_rows();
_model.publish_grid_settings(_grid_settings);
}
}
void load_previous() {
var cur = selected_previous_state;
selected_previous_state = null;
_model.load_previous_state(cur);
void on_grid_settings(VolSurfaceMacroGridSettings new_settings) {
using var _ = grid.defer_invalidate_rows();
_grid_settings = new_settings;
grid.load_from(_grid_settings);
grid.invalidate_rows();
_model.publish_grid_settings(_grid_settings);
}
}
public VolSurfaceGridVM grid { get; }
public VolSurfaceGraphVM vol_curve_vm { get; }
public VolTermsGraphVM vol_terms_vm { get; }
public VolSurfaceMacroActionsVM macro_actions { get; }
public VolSurfaceGlobalParameterVM globals { get; }
public VolSurfaceGridVM grid { get; private set; }
public VolSurfaceGraphVM vol_curve_vm { get; private set; }
public VolTermsGraphVM vol_terms_vm { get; private set; }
public VolSurfaceMacroActionsVM macro_actions { get; private set; }
public VolSurfaceGlobalParameterVM globals { get; private set; }
public bool ignore_implied_vol_settings {
get => _ignore_implied_vol_settings;
set {
if (Set(ref _ignore_implied_vol_settings, value)) {
_model.publish_ignore_implied_vol_settings(_request_id, value);
}
}
}
private bool _ignore_implied_vol_settings;
public bool ignore_implied_vol_settings { get { return _ignore_implied_vol_settings; } set { _model.publish_ignore_implied_vol_settings(_request_id, _ignore_implied_vol_settings = value); } }
public bool is_dirty { get { return _model.is_dirty; } }
public IRaiseCanExecuteChangedCommand revert_command { get; private set; }
public IRaiseCanExecuteChangedCommand commit_command { get; private set; }
public IDialogCommand main_settings_command { get; private set; }
public IDialogCommand advanced_settings_command { get; private set; }
public IDialogCommand grid_settings_command { get; private set; }
public ICommand details_command => new DelegateCommand(_ => _show_details());
public ICommand load_previous_command { get; private set; }
public ObservableCollection<string> previous_states { get; } = new();
public string? selected_previous_state {
get => _selected_state;
private string _selected_state = string.Empty;
public string selected_previous_state {
get { return _selected_state; }
set {
if (Set(ref _selected_state, value)) {
load_previous_cmd.TryRaiseCanExecuteChanged();
}
_selected_state = value;
load_previous_command.TryRaiseCanExecuteChanged();
RaisePropertyChanged();
}
}
public bool is_dirty => _model.is_dirty;
public ICommand revert_cmd => _revert_cmd;
public ICommand commit_cmd => _commit_cmd;
public ICommand populate_empty_exps_cmd { get; }
public ICommand main_settings_cmd => _main_settings_cmd;
public ICommand advanced_settings_cmd => _advanced_settings_cmd;
public ICommand grid_settings_cmd => _grid_settings_cmd;
public ICommand details_command => new Command(_show_details);
public ICommand load_previous_cmd { get; }
public VolSurfaceWindowSettings get_startup_data() {
var rv = new VolSurfaceWindowSettings {
id = _vs_id,
@@ -207,20 +152,39 @@ namespace mbts.spark {
return rv;
}
public void Dispose() {
vol_curve_vm.Dispose();
vol_terms_vm.Dispose();
globals.Dispose();
if (grid != null) grid.Dispose();
main_settings_command.Dispose();
advanced_settings_command.Dispose();
grid_settings_command.Dispose();
Disposable.dispose(ref _model);
}
void raise_dirty_changed() {
RaisePropertyChanged("is_dirty");
revert_command.RaiseCanExecuteChanged();
commit_command.RaiseCanExecuteChanged();
}
void _on_grid_selection_changed(IEnumerable<VolSurfaceDisplayGridExpiration> selection) {
if (selection.TryGetFirst(out var selected)) {
var selected = selection.FirstOrDefault();
if (selected != null) {
vol_curve_vm.set_visible_expiration(selected);
_model.publish_new_grid_selection(_request_id, selected, vol_curve_vm.show_implied_vol);
}
macro_actions.selection_changed(selection);
}
void _show_details() =>
_model.show_details();
async Task<VolSurfaceSettings?> _get_volsurface_settings() =>
async Task<VolSurfaceSettings> _get_volsurface_settings() =>
(await _bus.subscribe(SparkTags.VolSurfaceCommittedOutputTag(_vs_id)).FirstOrDefaultAsync())
?.volsurface_input
?.surface_settings;
void _show_details() =>
_model.show_details();
}
}
@@ -1,22 +1,19 @@
namespace mbts.spark {
using bts.api;
using bts.collections;
using bts.api;
using bts.utils;
using mbts.analytics;
using mbts.collections;
using mbts.ui;
using mbts.ui.shell;
using mbts.analytics;
using mbts.collections;
using mbts.ui;
using mbts.ui.shell;
using Spark.Core;
using Spark.Core.Disposables;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Windows.Media;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Windows.Media;
namespace mbts.spark {
class VolTermsGraphVM : DisposableViewModelBase {
readonly VolSurfaceDisplayModel _model;
readonly DateTimeAxisVM _exp_terms_x_axis;
+9 -24
View File
@@ -5,9 +5,6 @@
using mbts.analytics;
using mbts.ui.controls;
using Spark.Core.Disposables;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -127,20 +124,6 @@
_log_bad_transition(_state, "set candidate grid");
}
public void populate_empty_expirations() {
bts.Log.Ui.info(String.Format("VolSurfaceDisplayModel.populate_expirations called with state: {0}",
_state.ToString()));
if (_state == DisplayModelState.Idle || _state == DisplayModelState.ResponseReady) {
DisplayModelData curr_data = _get_current_data();
VolSurfaceInput vs_inp =
VolSurfaceDataFunctions.populate_empty_expirations(curr_data.vs_output.volsurface_input);
_change_state(DisplayModelState.WaitingForCalcResponse);
_bus.post(SparkTags.VolSurfaceCalculationRequestTag(_vs_id),
new VolSurfaceCalculationRequest(vs_inp, _request_version_no++));
} else
_log_bad_transition(_state, "populate_expirations");
}
#endregion
#region Globals
@@ -160,7 +143,6 @@
return (_committed_data != null && _committed_data.vs_output != null) ? _committed_data.vs_output.volsurface_input.surface_parameters.vol_time : DateTime.MinValue;
}
public void set_candidate_vol_time(DateTime vol_time) {
bts.Log.Ui.info($"VolSurfaceDisplayModel.set_candidate_vol_time vs_id: {_vs_id} state: {_state.ToString()} vol_time: {vol_time}");
if (_state == DisplayModelState.Idle || _state == DisplayModelState.ResponseReady) {
DisplayModelData curr_data = _get_current_data();
if (curr_data != null) {
@@ -314,7 +296,7 @@
bool succ = false;
VolSurfaceInputSnapshot vs_sn = _input_snapshot_list.ToList().Find(v => v.save_marker == state_name);
if (vs_sn != null) {
var vs_inp = ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs_sn.data);
VolSurfaceInput vs_inp = VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(vs_sn.data);
if (vs_inp != null) {
_change_state(DisplayModelState.WaitingForCalcResponse);
_bus.post(SparkTags.VolSurfaceCalculationRequestTag(_vs_id),
@@ -337,7 +319,7 @@
public byte[] get_current_state() {
DisplayModelData curr_data = _get_current_data();
if (curr_data != null && curr_data.vs_output != null && curr_data.vs_output.volsurface_input != null)
return ProtobufSerializationHelper.serialize(curr_data.vs_output.volsurface_input);
return VolSurfaceUtilityFunctions.serialize_proto(curr_data.vs_output.volsurface_input);
else
return null;
}
@@ -345,7 +327,7 @@
/// Sets the state that is passed in bytes form. Returns
/// true is state is set successfully
public bool set_state(byte[] file_data) {
var vs_input = ProtobufSerializationHelper.deserialize<VolSurfaceInput>(file_data);
VolSurfaceInput vs_input = VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(file_data);
if (vs_input != null) {
if (_state == DisplayModelState.Idle || _state == DisplayModelState.ResponseReady) {
_change_state(DisplayModelState.WaitingForCalcResponse);
@@ -584,7 +566,9 @@
private void _change_state(DisplayModelState new_state) {
bool dirty_before = _translate_to_dirty(_state),
dirty_after = _translate_to_dirty(new_state);
bts.Log.Ui.info($"VolSurfaceDisplayModel._change_state vs_id: {_vs_id} {_state.ToString()}->{new_state.ToString()}");
// mbts.Logger.log(bts.log.Level.Info, bts.log.Subsystem.ui,
// String.Format("State change {0}->{1}", _state.ToString(), new_state.ToString()));
bts.Log.Ui.info(String.Format("State change {0}->{1}", _state.ToString(), new_state.ToString()));
_state = new_state;
if (dirty_before != dirty_after && on_dirty_change != null) {
_bus.post(SparkTags.VolSurfaceDirtyStateTag(_vs_id), dirty_after);
@@ -627,8 +611,9 @@
}
}
private void _log_bad_transition(DisplayModelState state, string action) {
bts.Log.Ui.error($"VoLSurfaceDisplayModel bad_transaction vs_id: {_vs_id} {state}:{action}");
private static void _log_bad_transition(DisplayModelState state, string action) {
//mbts.Logger.log(bts.log.Level.Error, bts.log.Subsystem.ui, String.Format("{0}:{1}", state, action));
bts.Log.Ui.error(String.Format("{0}:{1}", state, action));
}
private static bool _translate_to_dirty(DisplayModelState state) {
Loaded 100 of 1815 files, more files were not shown because too many files have changed in this diff. Show more