Compare commits

..
21 changed files with 988 additions and 875 deletions

No files matched your search

-3
View File
@@ -18,9 +18,6 @@ insert_anchor_links = "right"
- Fixed a number of problems with filtering on the Fills form
- On the Lean algo, OnToward and Away are now calculated with respect to the opposite inside market at time of the order launch
- Iceberg Spreaders with queue holders are not erroneously cancelled after the first fill
- Added security symbol column to fills window
- Re-organized ladder settings dialog to make it clearer and easier to use
## 2.1.4
### User Visible Changes
- Fixed handling of cancel button in security picker
+5
View File
@@ -1,6 +1,7 @@
#/bin/bash
#python -m mkdocs build -d site
cp -r ../../src/sdk/doc/* ./content/bts_spark_sdk/Server/
./run_zola.sh build
scp -r ./public bts@bluetradesys.com:/home/bts/doc/
@@ -13,3 +14,7 @@ sudo mv ./public/* /var/www/documentation/
EOF
rm -r public
cd ./content/bts_spark_sdk/server/
find . -not -name '_index.md' -delete
cd ../..
@@ -61,14 +61,6 @@ namespace mbts.spark {
equality_comparer: SecurityDataHelper.EqualityComparer.IDComparer,
comparer: Comparer<SecurityImmutable>.Default
), DataGridFilterKnownTemplates.DiscreteValues, DefaultColumnWidths.Security);
// symbol
add_col(Columns.Symbol, DefaultColumnHeaders.Symbol, r => r.security.Symbol,
DiscreteValuesFilterVM.Create<FillTuple, string>(
co2.UserSymbol.get_all().Select(u => u.symbol).Distinct().ToList(),
ft => ft.security?.Symbol ?? string.Empty,
nameof(OrderBookRowVM.symbol)),
DataGridFilterKnownTemplates.DiscreteValues,
DefaultColumnWidths.Symbol);
// order type
var order_type_filter = dv_filter(OrderDataHelper.all_order_types, r => r.order?.order_type() ?? OrderType.None);
add_col_expl(Columns.OrderType,
@@ -198,7 +190,6 @@ namespace mbts.spark {
case Columns.SecurityKey: return wrap(ft => ft.fill.SecurityKey);
case Columns.Side: return wrap_default(ft => ft.fill.Side);
case Columns.Size: return wrap(ft => ft.fill.LastShares);
case Columns.Symbol: return wrap(ft => ft.security?.Symbol ?? string.Empty);
case Columns.TimeInForce: return wrap_default(ft => ft.order?.time_in_force() ?? TimeInForce.Undefined);
case Columns.User: return wrap(ft => ft.order?.user() ?? string.Empty);
default: goto case Columns.FillTime;
@@ -7,23 +7,7 @@ namespace mbts.ui.spark {
/// Interaction logic for FillsView.xaml
/// </summary>
partial class FillsView : UserControl {
public enum Columns {
FillTime,
User,
Account,
Exchange,
Security,
Symbol,
TimeInForce,
OrderType,
Side,
Price,
Size,
FillKind,
FillKey,
OrderKey,
SecurityKey
}
public enum Columns { FillTime, User, Account, Exchange, Security, TimeInForce, OrderType, Side, Price, Size, FillKind, FillKey, OrderKey, SecurityKey }
public FillsView() =>
InitializeComponent();
@@ -66,10 +66,6 @@ namespace bts.shell.fills {
[ProtoMember(14)]
[DIYGridColumnID(nameof(Columns.FillKind))]
public Fill.Types.FillKind[] fill_kind { get; set; }
[ProtoMember(15)]
[DIYGridColumnID(nameof(Columns.Symbol))]
public string[] symbol { get; set; }
}
static class FillsFilterStatesExtensions {
@@ -90,7 +86,6 @@ namespace bts.shell.fills {
pb.add_discrete_values(fs.order_type, ft => ft.order_type());
pb.add_discrete_values(fs.side, ft => ft.fill.Side);
pb.add_discrete_values(fs.fill_kind, ft => ft.fill.FillKind);
pb.add_discrete_values(fs.symbol, ft => ft.security?.Symbol ?? string.Empty);
// numeric
pb.add_numeric(fs.size, ft => ft.fill.LastShares);
pb.add_numeric(fs.price, ft => ft.fill.LastPrice);
@@ -40,7 +40,6 @@ namespace bts.shell.fills {
static class DefaultColumns {
public static GridColumnSettings security => new GridColumnSettings(col_id(Columns.Security), DefaultColumnHeaders.Security, width: DefaultColumnWidths.Security);
public static GridColumnSettings symbol => new GridColumnSettings(col_id(Columns.Symbol), DefaultColumnHeaders.Symbol, width: DefaultColumnWidths.Symbol);
public static GridColumnSettings fill_time => new GridColumnSettings(col_id(Columns.FillTime), DefaultColumnHeaders.FillTime, width: DefaultColumnWidths.Time);
public static GridColumnSettings user => new GridColumnSettings(col_id(Columns.User), DefaultColumnHeaders.User, width: DefaultColumnWidths.User);
public static GridColumnSettings account => new GridColumnSettings(col_id(Columns.Account), DefaultColumnHeaders.Account, width: DefaultColumnWidths.Account);
@@ -63,7 +62,6 @@ namespace bts.shell.fills {
public static IEnumerable<GridColumnSettings> all {
get {
yield return security;
yield return symbol;
yield return fill_time;
yield return user;
yield return account;
@@ -327,15 +327,7 @@ namespace mbts.spark {
public enum BadgeStyle { Normal, Alternate }
// TODO: rename to PriceDisplayFormat (today is merge monday, since this isn't a functional change, it is not worth the potential merge headaches right now)
public enum NetChangeTerms {
[Description("Standard Ticks")]
None,
[Description("Net Change Dollars")]
Dollars,
[Description("Net Change Ticks")]
Ticks
}
public enum NetChangeTerms { None, Dollars, Ticks }
[ProtoMember(1)]
public double row_height { get; set; }
@@ -23,7 +23,6 @@ namespace mbts.spark {
readonly Property<LadderSettings.BadgeStyle> _badge_style;
readonly Property<uint> _alternate_order_size;
readonly DelegateProperty<double> _row_height;
LadderSettings.NetChangeTerms _price_format;
Func<double> _get_order_entry_panel_width, _get_zoom_factor;
LadderSettings _current;
LadderColumnSettingsVM
@@ -31,8 +30,8 @@ namespace mbts.spark {
_bid = new LadderColumnSettingsVM("Bid"),
_price = new LadderColumnSettingsVM("Price"),
_ask = new LadderColumnSettingsVM("Ask"),
_last = new LadderColumnSettingsVM("Last", LadderSettingsView.LastColumnTemplateKey, true),
_piq = new LadderColumnSettingsVM("PIQ", can_toggle_show: true);
_last = new LadderColumnSettingsVM("Last", true),
_piq = new LadderColumnSettingsVM("PIQ", true);
VolumeColumnVM _volume = new VolumeColumnVM();
LadderMarketBreakLineVM
_bid_mkt_line = new LadderMarketBreakLineVM("Bid"),
@@ -60,6 +59,10 @@ namespace mbts.spark {
_cancel_buys_visibility = new OrderEntryPanelItemVisibilityVM("Cancel Buys"),
_cancel_sells_visibility = new OrderEntryPanelItemVisibilityVM("Cancel Sells"),
_cancel_all_visibility = new OrderEntryPanelItemVisibilityVM("Cancel All");
readonly Property<bool>
_show_in_net_change,
_show_in_net_change_dollars,
_show_in_net_change_ticks;
public LadderSettingsVM(OrdersModel model, bool is_synthetic, Func<double> get_left_panel_width, Func<double> get_zoom_factor) {
this.is_synthetic = is_synthetic;
@@ -71,6 +74,10 @@ namespace mbts.spark {
_alternate_order_size = backing<uint>(nameof(alternate_order_size));
_get_order_entry_panel_width = get_left_panel_width;
_get_zoom_factor = get_zoom_factor;
_show_in_net_change = backing<bool>(nameof(show_in_net_change));
_show_in_net_change_dollars = backing<bool>(nameof(show_in_net_change_dollars));
_show_in_net_change_ticks = backing<bool>(nameof(show_in_net_change_ticks));
// be sure to initialize backings before this measure_row_height call
_row_height = backing(nameof(row_height), () => LadderRender.measure_row_height(get_result()));
_orders.font_size_changed += on_font_size_changed;
@@ -103,8 +110,6 @@ namespace mbts.spark {
}
public MarketSizeDisplayVM size_display { get; } = new MarketSizeDisplayVM();
public LadderSettings.NetChangeTerms price_format { get => _price_format; set => Set(ref _price_format, value); }
public IEnumerable<LadderSettings.NetChangeTerms> price_format_options => EnumHelper.get_values<LadderSettings.NetChangeTerms>();
public FavoriteAlgosVM favorite_algos_vm { get; }
public double row_height => _row_height.Value;
@@ -170,6 +175,32 @@ namespace mbts.spark {
}
}
public bool show_in_net_change {
get => _show_in_net_change.Value;
set {
// when unchecking, clear out dollars and ticks
if (!value) {
show_in_net_change_dollars = false;
show_in_net_change_ticks = false;
}
// when checking, by defalt check dollars
if (value) {
show_in_net_change_dollars = true;
}
_show_in_net_change.Value = value;
}
}
public bool show_in_net_change_dollars {
get => _show_in_net_change_dollars.Value;
set => _show_in_net_change_dollars.Value = value;
}
public bool show_in_net_change_ticks {
get => _show_in_net_change_ticks.Value;
set => _show_in_net_change_ticks.Value = value;
}
public string key => GridSettingsTemplateKeys.Ladder;
public void load(LadderSettings settings) {
@@ -210,11 +241,13 @@ namespace mbts.spark {
_cancel_buys_visibility.show = settings.cancel_buys_visible;
_cancel_sells_visibility.show = settings.cancel_sells_visible;
_cancel_all_visibility.show = settings.cancel_all_visible;
price_format = settings.net_change;
// do not read the order entry panel width here from settings
// because it could have changed from the UI
// there might be a better way of doing this, like how
// does the widths of the ladder grid column pull this off?
show_in_net_change = settings.net_change != LadderSettings.NetChangeTerms.None;
show_in_net_change_dollars = settings.net_change == LadderSettings.NetChangeTerms.Dollars;
show_in_net_change_ticks = settings.net_change == LadderSettings.NetChangeTerms.Ticks;
}
public LadderSettings get_result() {
@@ -258,8 +291,19 @@ namespace mbts.spark {
clone.order_entry_panel_initial_width = _get_order_entry_panel_width();
clone.zoom_slider_visible = _zoom_slider_visbility.show;
clone.zoom_factor = _get_zoom_factor();
clone.net_change = price_format;
clone.net_change = _create_net_change_terms(show_in_net_change_dollars, show_in_net_change_ticks);
return clone;
LadderSettings.NetChangeTerms _create_net_change_terms(bool dollars, bool ticks) {
if (dollars) {
return LadderSettings.NetChangeTerms.Dollars;
}
if (ticks) {
return LadderSettings.NetChangeTerms.Ticks;
}
return LadderSettings.NetChangeTerms.None;
}
}
public void Dispose() => favorite_algos_vm.Dispose();
@@ -279,12 +323,11 @@ namespace mbts.spark {
readonly DelegateProperty<FontWeight> _font_weight;
readonly DelegateProperty<string> _font_display_name;
readonly Property<bool> _show;
readonly string _template_key;
readonly bool _can_toggle_visibility;
public LadderColumnSettingsVM(string name, string template_key = null, bool can_toggle_show = false) {
public LadderColumnSettingsVM(string name, bool can_toggle_visibility = false) {
this.name = name;
_template_key = template_key;
this.can_toggle_show = can_toggle_show;
_can_toggle_visibility = can_toggle_visibility;
foreground_palettes = new ObservableCollection<ColorPaletteVM>(ColorPalette.all_presets().Select(p => new ColorPaletteVM(p)));
background_palettes = new ObservableCollection<ColorPaletteVM>(ColorPalette.all_presets().Select(p => new ColorPaletteVM(p)));
_show = backing(nameof(show), true);
@@ -297,14 +340,8 @@ namespace mbts.spark {
_font_display_name = backing(nameof(font_display_name),
() => TextUtils.display_name(font_family, font_weight, font_size), nameof(font_family), nameof(font_weight), nameof(font_size));
_font_size.Changed += (oldval, newval) => font_size_changed?.Invoke(oldval, newval);
toggle_show_details_cmd = new DelegateCommand(() => {
show_details = !show_details;
RaisePropertyChanged(nameof(show_details));
});
}
public event Action<double, double> font_size_changed;
public string name { get; }
public Typeface typeface { get => _typeface.Value; set => _typeface.Value = value; }
public FontFamily font_family => _font_family.Value;
@@ -313,17 +350,14 @@ namespace mbts.spark {
public double font_size { get => _font_size.Value; set => _font_size.Value = value; }
public uint width { get; set; }
public bool show { get => _show.Value; set => _show.Value = value; }
public bool can_toggle_show { get; }
public bool show_details { get; private set; }
public Color foreground { get => _foreground.Value; set => _foreground.Value = value; }
public Color background { get => _background.Value; set => _background.Value = value; }
public ObservableCollection<ColorPaletteVM> foreground_palettes { get; }
public ObservableCollection<ColorPaletteVM> background_palettes { get; }
public event Action<double, double> font_size_changed;
public virtual string sample_text => "999-56789.01234";
public ICommand toggle_show_details_cmd { get; }
string ITemplateSelectorKey.key => _template_key;
string ITemplateSelectorKey.key => _can_toggle_visibility ? ui.spark.LadderSettingsView.ColumnVisibilityToggleTemplateKey : null;
public void assign_from(LadderColumnSettings settings) {
typeface = new Typeface(
@@ -361,7 +395,7 @@ namespace mbts.spark {
public Brush badge_border { get; } = new SolidColorBrush(BTSColors.MarketData.ask);
public Brush badge_background { get; } = Brushes.White;
string ITemplateSelectorKey.key => ui.spark.LadderSettingsView.OrdersColumnTemplateKey;
string ITemplateSelectorKey.key => ui.spark.LadderSettingsView.OrdersColumnSampleTemplateKey;
}
public class LadderMarketBreakLineVM : ViewModelBase {
@@ -429,7 +463,7 @@ namespace mbts.spark {
}
}
public LadderColumnSettingsVM general { get; } = new LadderColumnSettingsVM("Volume", LadderSettingsView.VolumeColumnTemplateKey, true);
public LadderColumnSettingsVM general { get; } = new LadderColumnSettingsVM("Volume", true);
public VolumeAtPriceAnimationVM buy { get; }
public VolumeAtPriceAnimationVM sell { get; }
public VolumeAtPriceAnimationVM passive { get; }
@@ -337,7 +337,6 @@ namespace mbts.spark {
if (e.ChangedButton == MouseButton.Middle) {
if (bs.HasValue) {
_send_parameterized_order(point, bs.Value);
return;
} else if (column.column_type == ColumnType.Price) {
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown (Key.RightShift) ||
Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt)) {
@@ -345,7 +344,6 @@ namespace mbts.spark {
} else {
_scroll_to_center();
}
return;
}
}
var pbs = (price, bs, e.ChangedButton);
File diff suppressed because it is too large. Load diff
@@ -10,15 +10,10 @@ namespace mbts.ui.spark {
/// </summary>
partial class LadderSettingsView : UserControl {
public const string
OrdersColumnTemplateKey = nameof(OrdersColumnTemplateKey),
VolumeColumnTemplateKey = nameof(VolumeColumnTemplateKey),
LastColumnTemplateKey = nameof(LastColumnTemplateKey),
OrdersColumnSampleTemplateKey = nameof(OrdersColumnSampleTemplateKey),
ColumnVisibilityToggleTemplateKey = nameof(ColumnVisibilityToggleTemplateKey),
FavoriteAlgoAddButtonTemplateKey = nameof(FavoriteAlgoAddButtonTemplateKey);
public static readonly IMultiValueConverter LadderColumnToggleShowToolTipConverter =
ValueConverter.create<bool, bool, string, string>((can_toggle_show, show, col_name) =>
can_toggle_show ? $"{(show ? "Hide" : "Show")} {col_name}" : $"{col_name} cannot be {(show ? "hidden" : "shown")}.");
public LadderSettingsView() =>
InitializeComponent();
@@ -77,7 +77,7 @@
</u:TemplateSelectorKeyValue>
<u:TemplateSelectorKeyValue Key="{x:Static usp:GridSettingsTemplateKeys.Ladder}">
<DataTemplate>
<usp:LadderSettingsView Margin="0,-16,0,0"/>
<usp:LadderSettingsView Margin="0,4,0,0"/>
</DataTemplate>
</u:TemplateSelectorKeyValue>
<u:TemplateSelectorKeyValue Key="{x:Static usp:GridSettingsTemplateKeys.OrderBook}">
+163 -4
View File
@@ -76,7 +76,7 @@ namespace bts.tests
);
var spreader_order1_response = await OrderUtilities.send_order(_order_service, order1_def, -0.30, 1);
Assert.IsTrue(spreader_order1_response.success, "Failed to send first spreader order");
Assert.IsTrue(spreader_order1_response.success, "Failed to send spreader order");
var (spreader_order_is_working, working_spreader_order1) = await verify_order_status(spreader_order1_response.value.OrderKey, OrderStatus.Working);
Assert.IsTrue(spreader_order_is_working, "Spreader order is not Working");
@@ -120,6 +120,156 @@ namespace bts.tests
}
[Test(Timeout = 300000)]
public async Task spreader_lean_qty_factor() {
await setup_spreader_tests();
string test_symbol = "SI";
var test_user = (name: "bts", id: 1u);
var test_account = (name: "ACC A", id: 1u);
(SecurityImmutable s1, SecurityImmutable s2) test_securities = await SpreaderUtilities.get_securities_for_common_setup_one(_md_relay, test_symbol);
var setup_product = await SpreaderUtilities.common_setup_one(_order_service, _synthetic_service, test_securities, test_account, test_user);
var order1_def = OrderDefinitionUtilities.create_spreader_order_def(
setup_product.synthetic.security,
Side.Buy,
setup_product.synthetic.strategy,
test_account,
test_user
);
var spreader_order1_response = await OrderUtilities.send_order(_order_service, order1_def, -0.30, 1);
Assert.IsTrue(spreader_order1_response.success, "Failed to send spreader order");
var (spreader_order_is_working, working_spreader_order1) = await verify_order_status(spreader_order1_response.value.OrderKey, OrderStatus.Working);
Assert.IsTrue(spreader_order_is_working, "Spreader order is not Working");
var (quoting_order_is_working, working_quoting_order) = await verify_child_order_status(spreader_order1_response.value.OrderKey, OrderStatus.Working);
Assert.IsTrue(quoting_order_is_working, "Order is not Working");
Assert.IsTrue(working_quoting_order.Value.State.Price == 18.6, "Quoting order has the wrong price");
Assert.IsTrue(await OrderUtilities.cancel_orders(_order_service, new List<OrderRecordImmutable> {working_spreader_order1.Value}), "Failed to cancel order");
var (quoting_order_is_canceled, canceled_quoting_order) = await verify_child_order_status(spreader_order1_response.value.OrderKey, OrderStatus.Canceled);
Assert.IsTrue(quoting_order_is_canceled, "Quoting order may not have been canceled");
// change the synthetic
var hedge_leg = setup_product.synthetic.strategy.LegParamsMap.Where(m => !m.Value.IsActiveQuoting).TryFirst();
Assert.IsTrue(hedge_leg.HasValue, "you need more legs");
foreach(var key in setup_product.synthetic.strategy.LegParamsMap.Keys) {
if(!setup_product.synthetic.strategy.LegParamsMap[key].IsActiveQuoting) {
setup_product.synthetic.strategy.LegParamsMap[key].QuoteParams.LeanQuantityRatio = 2d;
break;
}
}
Assert.IsTrue(await SpreaderUtilities.save_strategy(_synthetic_service, setup_product.synthetic.security.Id, (ExecutionStrategyImmutable) setup_product.synthetic.strategy), "Failed to save strategy");
var order2_def = OrderDefinitionUtilities.create_spreader_order_def(
setup_product.synthetic.security,
Side.Buy,
setup_product.synthetic.strategy,
test_account,
test_user
);
var spreader_order2_response = await OrderUtilities.send_order(_order_service, order2_def, -0.30, 1);
Assert.IsTrue(spreader_order2_response.success, "Failed to send spreader order");
var (spreader_order2_is_working, working_spreader_order2) = await verify_order_status(spreader_order2_response.value.OrderKey, OrderStatus.Working);
Assert.IsTrue(spreader_order2_is_working, "Spreader order is not Working");
var (quoting_order2_is_working, working_quoting_order2) = await verify_child_order_status(spreader_order2_response.value.OrderKey, OrderStatus.Working);
Assert.IsTrue(quoting_order2_is_working, "Order is not Working");
Assert.IsTrue(working_quoting_order2.Value.State.Price == 18.61, "Quoting order has the wrong price");
Assert.IsTrue(await OrderUtilities.cancel_orders(_order_service, new List<OrderRecordImmutable> {working_spreader_order2.Value}), "Failed to cancel order");
var (quoting_order2_is_canceled, canceled_quoting_order2) = await verify_child_order_status(spreader_order2_response.value.OrderKey, OrderStatus.Canceled);
Assert.IsTrue(quoting_order2_is_canceled, "Quoting order may not have been canceled");
// Order 3
foreach(var key in setup_product.synthetic.strategy.LegParamsMap.Keys) {
if(!setup_product.synthetic.strategy.LegParamsMap[key].IsActiveQuoting) {
setup_product.synthetic.strategy.LegParamsMap[key].QuoteParams.LeanQuantityRatio = 4d;
break;
}
}
Assert.IsTrue(await SpreaderUtilities.save_strategy(_synthetic_service, setup_product.synthetic.security.Id, (ExecutionStrategyImmutable) setup_product.synthetic.strategy), "Failed to save strategy");
var order3_def = OrderDefinitionUtilities.create_spreader_order_def(
setup_product.synthetic.security,
Side.Buy,
setup_product.synthetic.strategy,
test_account,
test_user
);
var spreader_order3_response = await OrderUtilities.send_order(_order_service, order3_def, -0.30, 1);
Assert.IsTrue(spreader_order3_response.success, "Failed to send spreader order");
var (spreader_order3_is_working, working_spreader_order3) = await verify_order_status(spreader_order3_response.value.OrderKey, OrderStatus.Working);
Assert.IsTrue(spreader_order3_is_working, "Spreader order is not Working");
var (quoting_order3_is_working, working_quoting_order3) = await verify_child_order_status(spreader_order3_response.value.OrderKey, OrderStatus.Working);
Assert.IsTrue(quoting_order3_is_working, "Order is not Working");
Assert.IsTrue(working_quoting_order3.Value.State.Price == 18.63, "Quoting order has the wrong price");
Assert.IsTrue(await OrderUtilities.cancel_orders(_order_service, new List<OrderRecordImmutable> {working_spreader_order3.Value}), "Failed to cancel order");
var (quoting_order3_is_canceled, canceled_quoting_order3) = await verify_child_order_status(spreader_order3_response.value.OrderKey, OrderStatus.Canceled);
Assert.IsTrue(quoting_order3_is_canceled, "Quoting order may not have been canceled");
// Order 4
foreach(var key in setup_product.synthetic.strategy.LegParamsMap.Keys) {
if(!setup_product.synthetic.strategy.LegParamsMap[key].IsActiveQuoting) {
setup_product.synthetic.strategy.LegParamsMap[key].QuoteParams.LeanQuantityRatio = 5d;
break;
}
}
Assert.IsTrue(await SpreaderUtilities.save_strategy(_synthetic_service, setup_product.synthetic.security.Id, (ExecutionStrategyImmutable) setup_product.synthetic.strategy), "Failed to save strategy");
var order4_def = OrderDefinitionUtilities.create_spreader_order_def(
setup_product.synthetic.security,
Side.Buy,
setup_product.synthetic.strategy,
test_account,
test_user
);
var spreader_order4_response = await OrderUtilities.send_order(_order_service, order4_def, -0.30, 1);
Assert.IsTrue(spreader_order4_response.success, "Failed to send spreader order");
var (spreader_order4_is_working, working_spreader_order4) = await verify_order_status(spreader_order4_response.value.OrderKey, OrderStatus.Working);
Assert.IsTrue(spreader_order4_is_working, "Spreader order is not Working");
var no_quoting_order4 = await get_order(ord => ord.ParentKey == spreader_order4_response.value.OrderKey, TimeSpan.FromSeconds(10));
Assert.IsFalse(no_quoting_order4.HasValue, "There should not have been a quoting order here...");
OrderRecordImmutable order_from_book = setup_product.book.Where(ordi => ordi.State.Price == 18.30).First();
var mod_resp = await OrderUtilities.modify_order(_order_service, order_from_book, 2);
Assert.IsTrue(mod_resp.success, "Order size was not changed");
var (quoting_order4_is_working, working_quoting_order4) = await verify_child_order_status(spreader_order4_response.value.OrderKey, OrderStatus.Working);
Assert.IsTrue(quoting_order4_is_working, "Order is not Working");
Assert.IsTrue(working_quoting_order4.Value.State.Price == 18.63, "Quoting order has the wrong price");
var mod_resp2 = await OrderUtilities.modify_order(_order_service, order_from_book, 1);
Assert.IsTrue(mod_resp.success, "Order size was not changed");
var (quoting_order5_is_canceled, canceled_quoting_order5) = await verify_child_order_status(spreader_order4_response.value.OrderKey, OrderStatus.Canceled);
Assert.IsTrue(quoting_order5_is_canceled, "Order was not canceld");
Assert.IsTrue(await OrderUtilities.cancel_orders(_order_service, new List<OrderRecordImmutable> {working_spreader_order4.Value}), "Failed to cancel order");
}
private async Task<(Boolean, OrderRecordImmutable?)> verify_child_order_status(uint parent_order_key, OrderStatus expected_status) {
var order = await get_order(ordi => ordi.ParentKey == parent_order_key && ordi.State.Status == expected_status);
return (order.HasValue && order.Value.State.Status == expected_status, order);
@@ -140,13 +290,22 @@ namespace bts.tests
return order.HasValue && (Math.Truncate(order.Value.State.Price * precision) == precision * expected_price);
}
private async Task<OrderRecordImmutable?> get_order(Func<OrderRecordImmutable, bool> predicate)
private async Task<OrderRecordImmutable?> get_order(Func<OrderRecordImmutable, bool> predicate, TimeSpan? timeout = null)
{
if(timeout == null){
timeout = TimeSpan.FromSeconds(60);
}
var orders = await OrderUtilities.wait_for_filtered_orders(_order_service,
o => o.Where(predicate).Count() > 0,
ord => ord.Where(predicate),
TimeSpan.FromSeconds(30));
return orders.result.TryFirst();
timeout);
if(orders.result != null) {
return orders.result.TryFirst();
}
else {
return null;
}
}
@@ -75,6 +75,10 @@ namespace bts.tests
});
var tr = await tcs.Task.timeout(timeout.Value);
sub.Dispose();
if(tr.result == null) {
Console.WriteLine("Timed out while retreving orders.");
}
return tr;
}
@@ -124,7 +128,7 @@ namespace bts.tests
}
/// <summary>
/// We should replace with something like the OrderDataHeler from the Spark project.
/// We should replace with something like the OrderDataHelper from the Spark project.
/// </summary>
public static class OrderDefinitionUtilities {
@@ -27,8 +27,24 @@ namespace bts.tests
Assert.IsNotNull(exps);
Assert.IsTrue(exps.Count() > 2, "Need at least two expirations");
var exp1 = exps[0];
var exp2 = exps[1];
(uint, uint) preferred_expirations = (07,12);
FutureContract exp1;
FutureContract exp2;
if(exps.Exists(expir => expir.ExpirationMonth == preferred_expirations.Item1)) {
exp1 = exps.Where(ex => ex.ExpirationMonth == preferred_expirations.Item1).First();
}
else {
exp1 = exps[0];
}
if(exps.Exists(expir => expir.ExpirationMonth == preferred_expirations.Item2 && expir.ExpirationYear == exp1.ExpirationYear)) {
exp2 = exps.Where(ex => ex.ExpirationMonth == preferred_expirations.Item2 && ex.ExpirationYear == exp1.ExpirationYear).First();
}
else {
exp2 = exps[1];
}
Func<ChannelUpdate, bool> sec1_match = ch =>
ch.Security.Future.ExpirationYear == exp1.ExpirationYear &&
@@ -103,13 +119,15 @@ namespace bts.tests
new_synth.Synthetic.Legs.Add(legs.Select(l => l.contract));
new_synth.Symbol = deduce_symbol(new_synth);
new_synth.ContractSpec = new ContractSpecification();
new_synth.ContractSpec.LowTick = 0.01;
new_synth.ContractSpec.HighTick = 0.01;
new_synth.ContractSpec.LowTick = 0.005;
new_synth.ContractSpec.HighTick = 0.005;
new_synth.ContractSpec.PriceBreak = double.MaxValue;
new_synth.ContractSpec.MainFraction = 1u;
new_synth.ContractSpec.PriceDisplayFormat = 3u;
new_synth.ContractSpec.CashPerPoint = 1u;
new_synth.ContractSpec.PriceMultiplier = 1u;
new_synth.Exchange = Venue.Bts;
new_synth.Synthetic.Name = "TEST_SYNTH" + DateTime.Now.ToString();
new_synth.Synthetic.Name = "TEST_SYNTH" + DateTime.Now.TimeOfDay.ToString();
var result = await service.create_synthetic_async(new_synth);
Assert.IsTrue(result.success, "Unable to create synthetic");
@@ -0,0 +1,52 @@
#!/bin/bash
if [ -d ~/sparkdata/ ]
then
sparkdata_dir=~/sparkdata
else
sparkdata_dir=/sparkdata
fi
./delete_dbs.sh
config=$sparkdata_dir/conf/spark.conf
bak=$sparkdata_dir/conf/spark.conf.bak
[ ! -d "$sparkdata_dir/conf" ] && mkdir $sparkdata_dir/conf/
[ -f "$conf" ] && mv $conf $bak
cat << EOF > $sparkdata_dir/conf/spark.conf
ExchangeSim {
value {
merge_with_md:false
}
}
Logging {
value {
console { default_level: "Error" }
syslog { default_level: "Error" }
file { default_level: "Error" }
}
}
SymbolList {
value {
symbol: "SI"
}
}
EOF
nohup ./sparkd run &
pid=$!
echo "sparkd pid: " $pid
dotnet sparkcmd.dll test spreader_lean_qty_factor
exit_status=$?
pkill -P $$
[ -f "$bak" ] && mv $bak $conf
[ $exit_status -eq 0 ] && echo "Test Finished" || echo "Test failed"
exit $exit_status
+8 -4
View File
@@ -58,7 +58,7 @@ namespace interop {
// Functions used for interop to other languages
/////////////////////////////////////////////////
std::string getbuffer_serialized_buffer;
extern "C" BTS_EXPORT const char* get_buffer(const char* key_name, int& out_length)
{
@@ -69,7 +69,7 @@ extern "C" BTS_EXPORT const char* get_buffer(const char* key_name, int& out_leng
getbuffer_serialized_buffer.clear();
message.SerializePartialToString(&getbuffer_serialized_buffer);
out_length = getbuffer_serialized_buffer.size();
return getbuffer_serialized_buffer.c_str();
}
@@ -89,10 +89,14 @@ namespace internal {
// Functions used in testing
//////////////////////////////////////////
extern "C" BTS_EXPORT void initialize_for_test(const std::string& values, bool print_errors)
extern "C" BTS_EXPORT void initialize_for_test(const char* values, bool print_errors)
{
config_state.reset();
config_state.load_string(values, print_errors);
config_state.load_string(std::string(values), print_errors);
}
void initialize_for_test(const std::string& value, bool print_errors) {
config_state.reset();
config_state.load_string(value, print_errors);
}
extern "C" BTS_EXPORT void reset()
+3 -2
View File
@@ -22,7 +22,7 @@ namespace config {
// Load and initialize config.
// This will be automatically called on the first key request but since loading config
// can result in network requests this function is available for applications that want to
// manage pauses in execution.
// manage pauses in execution.
// Ex: initialize() on a background thread so that config::get<T>() is fast on a UI thread
extern "C" BTS_EXPORT void initialize();
@@ -56,7 +56,8 @@ namespace config {
{
// Initialize configuration state from a string instead of from the filesystem. defaults.conf will still be loaded.
// Calling this a second time clears all values from previous initialization
extern "C" BTS_EXPORT void initialize_for_test(const std::string& configuration, bool print_errors=true);
extern "C" BTS_EXPORT void initialize_for_test(const char* configuration, bool print_errors=true);
void initialize_for_test(const std::string& configuration, bool print_errors=true);
// Releases all resources and returns config to factory defaults
extern "C" BTS_EXPORT void reset();
@@ -2,9 +2,9 @@ This test verifies that fractional hedges work. That is, when a fill in a quotin
not equate to one full contract in the hedging leg, we accumulate the unhedged
delta, until we can send one or more hedging contracts.
1. Create a new synthetic spread. For the legs choose SIF9 and SIH9 (if you dont
1. Create a new synthetic spread. For the legs choose SIF9 and SIH9 (if you don't
have these contracts, other contracts can be chosen too) and for the quantities choose 1 and -1.5
respectively (and same for the Price multiplier).
respectively (and same for the Price multiplier).
Enable quoting for SIH9, and disable all quoting, pre-hedge and post-hedge parameters.
Name the synthetic SIF9-1.5SIH9.
@@ -18,13 +18,13 @@ to enter orders). The quoting order will lean against this.
4. Verify that a 15 lot quoting order is sent for SIH9 at 19.935.
5. Now we will start filling the quoting order and verify the hedges. A 1 lot fill in the
quoting leg means a 2/3 contract in the hedging leg. Since we can not send 2/3 constracts,
quoting leg means a 2/3 contract in the hedging leg. Since we can not send 2/3 contracts,
we will add it to the "unhedged delta" till the unhedged delta > 1, and then we will send one
or more orders to get the unhedged delta < 1.
Force quoting fills based on the left most column (by lifting the quoting offer)
and verify that hedge orders of size "hedge_order_sent" (3rd column) are sent as a result.
The "unhedged_delta" column shows the unhedged delta immediatly after the quoting fill
The "unhedged_delta" column shows the unhedged delta immediately after the quoting fill
and the "remaining_unhedged_delta" column is the unhedged delta after the hedge order
has been sent.
You can check the hedge orders being sent easily by looking at the order reduction
@@ -10,7 +10,7 @@ ExchangeSim {
}
}
1. Open up the mview and find a security with with both direct and implied markets, on the ask side.
1. Open up the mview and find a security with with both direct and implied markets, on the ask side.
Make sure those markets are stable and you can rely on them.
2. Create a synthetic with the security in 1. being the hedge leg (buy) and choose a quoting
@@ -19,11 +19,11 @@ use "Merged"
3. Disable all spreader params.
4. Now enter a spreader order so that it doesnt get filled immediatly. Note the quoting order.
4. Now enter a spreader order so that it doesn't get filled immediately. Note the quoting order.
quoting leg price = hedge_price - spreader_price.
hedge_price is where it can buy the hedge order (which since its a buy will be on the ask side of
the hedging market).
Make sure thta its correct and its using the merged book in the hedging market.
Make sure that its correct and its using the merged book in the hedging market.
5. Cancel the order and change the spreader so its using Direct prices.
Repeat 4, and make sure its using direct price on the hedging market.
+3 -3
View File
@@ -5,8 +5,8 @@ with 1 quoting leg.
1. Create a 4 legged synthetic spread with legs SIF9, SIH9, SIK9, SIN9, with leg quantities and
price multipliers of 1,1,1 and -1 respectively. Leg SIN9 is the only quoting leg.
Disable all Quote, Pre-Hedge and Post-Hedge paramaters (leg contracts are arbitrary, so if you
dont have those contracts, choose any set of 4 contracts).
Disable all Quote, Pre-Hedge and Post-Hedge parameters (leg contracts are arbitrary, so if you
don't have those contracts, choose any set of 4 contracts).
2. Enter a synthetic buy order of 10 lots at 40.00. The ladders will most likely be empty, so
use the market view to enter orders.
@@ -16,7 +16,7 @@ Now enter:
SIH9 10 lot sell @ 19.950
SIK9 10 lot sell @ 20.200
There should still be no quoting order for SIN9 since the SIF9 hedge leg still doesnt have a market.
There should still be no quoting order for SIN9 since the SIF9 hedge leg still doesn't have a market.
Now Enter:
SIF9 1 lot sell @ 20.000