Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3f53d05c8 | ||
|
|
1b5f58c572 | ||
|
|
38bf38c62d | ||
|
|
4e08a43d0c | ||
|
|
4f912f99bd | ||
|
|
ae7e1761a7 | ||
|
|
4891eea5ba | ||
|
|
bc36db0480 | ||
|
|
cdaba74c06 | ||
|
|
b045307f30 | ||
|
|
60a7b504db | ||
|
|
0f62f14a1d | ||
|
|
87030dbb88 |
No files matched your search
@@ -1,3 +1,13 @@
|
||||
1.1.7
|
||||
- Fixed spread leg price fill
|
||||
- Fixed HO cash per point value
|
||||
|
||||
1.1.6
|
||||
- Fixed occasional crash when filtering fills
|
||||
- Fixed several cash per point multipliers
|
||||
- Colored time of sales row with aggressor side
|
||||
- Iceberg orders now cancel (rathern than error) when a child is canceled
|
||||
|
||||
1.1.0
|
||||
- Added per user self match protection, location and self match protection FIX tag settings
|
||||
- Implemented a new "Trigger Order" algo
|
||||
|
||||
@@ -6,11 +6,14 @@ using mbts.ui.controls;
|
||||
using mbts.ui.spark;
|
||||
using mbts.ui.utility;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using static bts.shell.TimeAndSalesWindowFactory;
|
||||
using static mbts.ui.controls.DIYGrid;
|
||||
|
||||
namespace mbts.spark {
|
||||
class TimeAndSalesVM : SecurityGrid<TimeAndSalesVM.Row, TradeInfo> {
|
||||
@@ -26,23 +29,32 @@ namespace mbts.spark {
|
||||
security_filter.load_state(filters.security);
|
||||
price_filter.load_state(filters.price);
|
||||
size_filter.load_state(filters.size);
|
||||
aggressor_filter.load_state(filters.aggressor_sides);
|
||||
trade_key_filter.load_state(filters.trade_key);
|
||||
security_key_filter.load_state(filters.security_key);
|
||||
}
|
||||
// Columns
|
||||
add_column(TimeAndSalesView.Columns.Security, "Security", DIYGrid.DefaultColumnWidths.Security, security_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_column(TimeAndSalesView.Columns.Time, "Time", DIYGrid.DefaultColumnWidths.Time, time_filter, DataGridFilterKnownTemplates.TimeFilter);
|
||||
add_column(TimeAndSalesView.Columns.Price, "Price", DIYGrid.DefaultColumnWidths.Price, price_filter, DataGridFilterKnownTemplates.DoubleMinMax);
|
||||
add_column(TimeAndSalesView.Columns.Size, "Size", DIYGrid.DefaultColumnWidths.Size, size_filter, DataGridFilterKnownTemplates.UIntMinMax);
|
||||
add_column(TimeAndSalesView.Columns.TradeKey, "Trade Key", DIYGrid.DefaultColumnWidths.TradeKey, trade_key_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_column(TimeAndSalesView.Columns.SecurityKey, "Security Key", DIYGrid.DefaultColumnWidths.SecurityKey, security_key_filter, DataGridFilterKnownTemplates.Regex);
|
||||
void add_column(TimeAndSalesView.Columns col_key, string header, double width, IDataGridColumnFilter filter, string filter_template) =>
|
||||
columns.Add(new DIYGrid.RenderTextColumn<Row>(r => r[col_key], filter, filter_template) { Header = header, Width = width });
|
||||
//
|
||||
add_column(TimeAndSalesView.Columns.Security, DefaultColumnHeaders.Security, DefaultColumnWidths.Security, security_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_column(TimeAndSalesView.Columns.Time, DefaultColumnHeaders.Time, DefaultColumnWidths.Time, time_filter, DataGridFilterKnownTemplates.TimeFilter);
|
||||
add_column(TimeAndSalesView.Columns.Price, DefaultColumnHeaders.Price, DefaultColumnWidths.Price, price_filter, DataGridFilterKnownTemplates.DoubleMinMax, System.Windows.HorizontalAlignment.Right);
|
||||
add_column(TimeAndSalesView.Columns.Size, DefaultColumnHeaders.Size, DefaultColumnWidths.Size, size_filter, DataGridFilterKnownTemplates.UIntMinMax, System.Windows.HorizontalAlignment.Right);
|
||||
add_column(TimeAndSalesView.Columns.Aggressor, DefaultColumnHeaders.Aggressor, DIYGrid.DefaultColumnWidths.Aggressor, aggressor_filter, DataGridFilterKnownTemplates.EnumValues);
|
||||
add_column(TimeAndSalesView.Columns.TradeKey, DefaultColumnHeaders.TradeKey, DIYGrid.DefaultColumnWidths.TradeKey, trade_key_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_column(TimeAndSalesView.Columns.SecurityKey, DefaultColumnHeaders.SecurityKey, DIYGrid.DefaultColumnWidths.SecurityKey, security_key_filter, DataGridFilterKnownTemplates.Regex);
|
||||
void add_column(TimeAndSalesView.Columns col_key, string header, double width, IDataGridColumnFilter filter, string filter_template, System.Windows.HorizontalAlignment h_alignment = System.Windows.HorizontalAlignment.Left) =>
|
||||
columns.Add(new TimeAndSalesColumn(
|
||||
r => r[col_key]
|
||||
, (r) => _get_aggressor_brush(r)
|
||||
, filter
|
||||
, filter_template
|
||||
)
|
||||
{ Header = header, Width = width, horizontal_alignment = h_alignment }
|
||||
);
|
||||
|
||||
_resources.AddRange(
|
||||
show_ladder,
|
||||
DataGridFilterHelper.hook_filters(
|
||||
rows_view, time_filter, security_filter, price_filter, size_filter, trade_key_filter, security_key_filter
|
||||
rows_view, time_filter, security_filter, price_filter, size_filter, aggressor_filter, trade_key_filter, security_key_filter
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -50,11 +62,22 @@ namespace mbts.spark {
|
||||
public ObservableCollection<DIYGrid.ColumnBase> columns { get; } = new ObservableCollection<DIYGrid.ColumnBase>();
|
||||
public DelegateCommandParamObserver<Row> show_ladder { get; }
|
||||
|
||||
private Brush _get_aggressor_brush(Row r) {
|
||||
BTSColor c;
|
||||
Brush b;
|
||||
if (r.aggressor_side == AggressorSide.Buy) c = BTSColors.MarketData.bid;
|
||||
else if (r.aggressor_side == AggressorSide.Sell) c = BTSColors.MarketData.ask;
|
||||
else c = Brushes.Transparent;
|
||||
(b = new SolidColorBrush(c) { Opacity = 0.33 }).Freeze();
|
||||
return b;
|
||||
}
|
||||
|
||||
#region Filters
|
||||
public IDataGridColumnPersistentFilter<Row, TimeFilterTuple> time_filter { get; } = new TimeFilterVM<Row>(r => r.time, nameof(Row.time));
|
||||
public IDataGridColumnPersistentFilter<Row, string> security_filter { get; }
|
||||
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> price_filter { get; } = new DoubleMinMax<Row>(r => r.price, nameof(Row.price));
|
||||
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> size_filter { get; } = new UIntMinMax<Row>(r => r.size, nameof(Row.size));
|
||||
public IDataGridColumnPersistentFilter<Row, AggressorSide[]> aggressor_filter { get; } = DiscreteValuesFilterVM.Create<Row, AggressorSide>(EnumHelper.get_values<AggressorSide>().ToArray(), r => r.aggressor_side, nameof(Row.aggressor_side));
|
||||
public IDataGridColumnPersistentFilter<Row, string> security_key_filter { get; } = new RegexFilterVM<Row>(r => r.security_key.ToString(), nameof(Row.security_key));
|
||||
public IDataGridColumnPersistentFilter<Row, string> trade_key_filter { get; } = new RegexFilterVM<Row>(r => r.trade_key.ToString(), nameof(Row.trade_key));
|
||||
|
||||
@@ -65,7 +88,8 @@ namespace mbts.spark {
|
||||
price = price_filter.get_state(),
|
||||
size = size_filter.get_state(),
|
||||
trade_key = trade_key_filter.get_state(),
|
||||
security_key = security_key_filter.get_state()
|
||||
security_key = security_key_filter.get_state(),
|
||||
aggressor_sides = aggressor_filter.get_state()
|
||||
};
|
||||
#endregion
|
||||
|
||||
@@ -90,6 +114,7 @@ namespace mbts.spark {
|
||||
_time_text,
|
||||
_price_text,
|
||||
_size_text,
|
||||
_aggressor_text,
|
||||
_trade_key_text,
|
||||
_security_key_text;
|
||||
|
||||
@@ -98,11 +123,13 @@ namespace mbts.spark {
|
||||
time = trade.Time.lldatetime();
|
||||
price = trade.Mantissa * Math.Pow(10, trade.Exponent);
|
||||
size = trade.Size;
|
||||
aggressor_side = trade.AggressorSide;
|
||||
show_ladder = new DelegateCommand(() => parent._show_ladder_async(this).ignore());
|
||||
_security_text = security.ToString();
|
||||
_time_text = time.ToString("M/d h:mm:ss tt");
|
||||
_price_text = security.ContractSpec.format(price);
|
||||
_size_text = size.ToString();
|
||||
_aggressor_text = aggressor_side.ToString();
|
||||
_trade_key_text = _trade_key.ToString();
|
||||
_security_key_text = security_key.ToString();
|
||||
}
|
||||
@@ -113,6 +140,7 @@ namespace mbts.spark {
|
||||
public DateTime time { get; }
|
||||
public double price { get; }
|
||||
public uint size { get; }
|
||||
public AggressorSide aggressor_side { get; }
|
||||
public ICommand show_ladder { get; }
|
||||
|
||||
public string this[TimeAndSalesView.Columns col] {
|
||||
@@ -122,6 +150,7 @@ namespace mbts.spark {
|
||||
case TimeAndSalesView.Columns.Time: return _time_text;
|
||||
case TimeAndSalesView.Columns.Price: return _price_text;
|
||||
case TimeAndSalesView.Columns.Size: return _size_text;
|
||||
case TimeAndSalesView.Columns.Aggressor: return _aggressor_text;
|
||||
case TimeAndSalesView.Columns.TradeKey: return _trade_key_text;
|
||||
case TimeAndSalesView.Columns.SecurityKey: return _security_key_text;
|
||||
default: return null;
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace mbts.ui.spark {
|
||||
/// Interaction logic for TimeAndSalesView.xaml
|
||||
/// </summary>
|
||||
partial class TimeAndSalesView : UserControl {
|
||||
public enum Columns { Time, Security, Price, Size, OrderType, TradeKey, SecurityKey }
|
||||
public enum Columns { Time, Security, Price, Size, OrderType, TradeKey, SecurityKey, Aggressor }
|
||||
|
||||
public TimeAndSalesView() =>
|
||||
InitializeComponent();
|
||||
|
||||
@@ -12,6 +12,7 @@ using System.Reactive.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using static bts.shell.TimeAndSalesWindowFactory;
|
||||
using static mbts.ui.controls.DIYGrid;
|
||||
|
||||
namespace mbts.spark {
|
||||
class TimeAndSalesWindow : SparkWindow<StartupData>, ISlowWindow {
|
||||
@@ -36,7 +37,16 @@ namespace mbts.spark {
|
||||
public override string window_type => _window_type;
|
||||
public override IEnumerable<SparkCommand> Commands => _commands;
|
||||
public override UIElement Content => _view;
|
||||
public override double MinWidth => 444 + SPARK_MENU_COLLAPSED_WIDTH + LAUNCHER_BUTTON_BORDER_WIDTH;
|
||||
public override double MinWidth => DefaultColumnWidths.Security
|
||||
+ DefaultColumnWidths.Time
|
||||
+ DefaultColumnWidths.Price
|
||||
+ DefaultColumnWidths.Size
|
||||
+ DefaultColumnWidths.Aggressor
|
||||
+ DefaultColumnWidths.TradeKey
|
||||
+ DefaultColumnWidths.SecurityKey
|
||||
+ SPARK_MENU_COLLAPSED_WIDTH
|
||||
+ LAUNCHER_BUTTON_BORDER_WIDTH;
|
||||
|
||||
public override StartupData SaveState => _state = new StartupData(_state.security_criteria, _vm.value.rows_view.GetSortingCriteria(), _vm.value.get_filter_states());
|
||||
|
||||
public override void Dispose() =>
|
||||
|
||||
@@ -70,6 +70,8 @@ namespace bts.shell {
|
||||
public string trade_key;
|
||||
[ProtoMember(6)]
|
||||
public string security_key;
|
||||
[ProtoMember(7)]
|
||||
public co2.AggressorSide[] aggressor_sides;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,8 @@ namespace mbts.ui.controls {
|
||||
Time = 100,
|
||||
TimeInForce = 47,
|
||||
TradeKey = 76,
|
||||
User = 53;
|
||||
User = 53,
|
||||
Aggressor = 80;
|
||||
}
|
||||
|
||||
public static class DefaultColumnHeaders {
|
||||
@@ -40,7 +41,9 @@ namespace mbts.ui.controls {
|
||||
Size = "Qty",
|
||||
TimeInForce = "TIF",
|
||||
TradeKey = "Trade Key",
|
||||
User = "User";
|
||||
User = "User",
|
||||
Time = "Time",
|
||||
Aggressor = "Aggressor";
|
||||
}
|
||||
|
||||
internal interface IKeyedColumn<TColKey> {
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
using mbts.spark;
|
||||
using mbts.spark.filters;
|
||||
using mbts.ui.utility.text;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace mbts.ui.controls {
|
||||
public partial class DIYGrid {
|
||||
internal class TimeAndSalesColumn : RenderTextColumn<TimeAndSalesVM.Row> {
|
||||
|
||||
readonly Func<TimeAndSalesVM.Row, string> _get_text;
|
||||
readonly Func<TimeAndSalesVM.Row, Brush> _get_brush;
|
||||
|
||||
public TimeAndSalesColumn(Func<TimeAndSalesVM.Row, string> get_text, Func<TimeAndSalesVM.Row, Brush> get_brush, IDataGridColumnFilter filter = null, string filter_template = null, GlyphContext glyph_context = null) : base(get_text, filter, filter_template, glyph_context) {
|
||||
_get_text = get_text;
|
||||
_get_brush = get_brush;
|
||||
}
|
||||
|
||||
public override void draw(TimeAndSalesVM.Row row, DrawingContext dc, ColumnGeometry position, double row_height) {
|
||||
CellRender.draw_text(dc
|
||||
, glyph_context
|
||||
, font_size
|
||||
, _get_text(row)
|
||||
, position
|
||||
, row_height
|
||||
, foreground
|
||||
, _get_brush(row)
|
||||
, horizontal_alignment
|
||||
, vertical_alignment
|
||||
, padding);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,17 +190,21 @@ namespace mbts.ui.controls
|
||||
}
|
||||
}
|
||||
|
||||
void item_Unselected(object sender, RoutedEventArgs e) {
|
||||
if (_selection_changing) return;
|
||||
var item = ((ListBoxItem)sender).DataContext;
|
||||
var selected_items = Selection;
|
||||
if (selected_items.Contains(item)) {
|
||||
using (_selection_change()) {
|
||||
selected_items.Remove(item);
|
||||
_update_is_all_selected();
|
||||
}
|
||||
}
|
||||
}
|
||||
void item_Unselected(object sender, RoutedEventArgs e) {
|
||||
if (!_selection_changing && sender is ListBoxItem container) {
|
||||
// the [ListBoxItem] sender may be "Disconnected" https://stackoverflow.com/questions/14282894/wpf-listbox-virtualization-creates-disconnecteditems/14358688
|
||||
var item = ItemContainerGenerator.ItemFromContainer(container);
|
||||
if (item != DependencyProperty.UnsetValue) {
|
||||
var selected_items = Selection;
|
||||
if (selected_items.Contains(item)) {
|
||||
using (_selection_change()) {
|
||||
selected_items.Remove(item);
|
||||
_update_is_all_selected();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void item_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) {
|
||||
using (_selection_change()) ((ListBoxItem)sender).IsSelected = Selection.Contains(e.NewValue);
|
||||
@@ -368,4 +372,4 @@ namespace mbts.ui.controls
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1399
-5505
File diff suppressed because it is too large.
Load diff
@@ -115,7 +115,7 @@ void MDProducerHandle::set_status(CoconutSecurityStatus status) {
|
||||
}
|
||||
}
|
||||
|
||||
void MDProducerHandle::add_trade(TimeStamp time, const PriceSize price, LLDateTime tradetime, uint32_t volume) {
|
||||
void MDProducerHandle::add_trade(TimeStamp time, const PriceSize price, LLDateTime tradetime, co2::AggressorSide agside, uint32_t volume) {
|
||||
cdata().last_trade.store(price);
|
||||
cdata().last_trade_time = tradetime;
|
||||
cdata().total_volume = volume;
|
||||
@@ -127,6 +127,7 @@ void MDProducerHandle::add_trade(TimeStamp time, const PriceSize price, LLDateTi
|
||||
trade.set_mantissa(price.mantissa());
|
||||
trade.set_size(price.size());
|
||||
trade.set_time(tradetime);
|
||||
trade.set_aggressor_side(agside);
|
||||
if (volume > 0) trade.set_total_volume(volume);
|
||||
trade.set_key(key());
|
||||
_channel.add_trade(trade);
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
void set_status(co2::CoconutSecurityStatus status); // hot
|
||||
|
||||
// Updates trade log and last trade
|
||||
void add_trade(TimeStamp time, const PriceSize pricesize, datetime::LLDateTime date, uint32_t total_volume=0); // cold
|
||||
void add_trade(TimeStamp time, const PriceSize pricesize, datetime::LLDateTime date, co2::AggressorSide agside, uint32_t total_volume=0); // cold
|
||||
// Update last_trade without updating trade log
|
||||
void set_last_trade(TimeStamp time, const PriceSize ps, datetime::LLDateTime date, uint32_t total_volume);
|
||||
void add_rfq(TimeStamp time, const co2::QuoteRequestMessage& rfq); // cold
|
||||
|
||||
@@ -119,6 +119,12 @@ message MiscMessage {
|
||||
double session_low_offer = 12;
|
||||
double fixing_price = 13;
|
||||
}
|
||||
|
||||
enum AggressorSide {
|
||||
AGGRESSOR_SIDE_NONE = 0;
|
||||
AGGRESSOR_SIDE_BUY = 1;
|
||||
AGGRESSOR_SIDE_SELL = 2;
|
||||
}
|
||||
|
||||
message TradeMessage {
|
||||
uint32 key = 1;
|
||||
@@ -130,6 +136,7 @@ message TradeMessage {
|
||||
uint32 size = 6;
|
||||
uint32 total_volume = 7;
|
||||
bool gap = 8;
|
||||
AggressorSide aggressor_side = 9;
|
||||
}
|
||||
message QuoteRequestMessage {
|
||||
enum Side {
|
||||
|
||||
@@ -474,7 +474,8 @@ void ExchangeSimApplication::update_md(std::string const &sec_desc) {
|
||||
utils::TimeStamp::now(),
|
||||
md::PriceSize::from_double<7>(t.price.value() * price_factor,
|
||||
t.quantity.value()),
|
||||
datetime::ll_now());
|
||||
datetime::ll_now(),
|
||||
co2::AGGRESSOR_SIDE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <vector>
|
||||
#include "lib/utils/helper_macros.h"
|
||||
#include "lib/config/protos/MarketData.pb.h"
|
||||
#include "lib/md/protos/co2.pb.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace bts::co2;
|
||||
@@ -349,11 +350,23 @@ void MDP3Listener::onBookUpdate(onixs::Handler&, const onixs::Security& sec, con
|
||||
//
|
||||
// Trades
|
||||
|
||||
void on_trade(SecurityData* data, const onixs::PRICE& price, int size, const onixs::Timestamp& onixs_date) {
|
||||
AggressorSide map_aggressor(onixs::AggressorSide::Enum agside) {
|
||||
switch(agside) {
|
||||
default:
|
||||
case onixs::AggressorSide::NoAggressor:
|
||||
return AGGRESSOR_SIDE_NONE;
|
||||
case onixs::AggressorSide::Buy:
|
||||
return AGGRESSOR_SIDE_BUY;
|
||||
case onixs::AggressorSide::Sell:
|
||||
return AGGRESSOR_SIDE_SELL;
|
||||
}
|
||||
}
|
||||
|
||||
void on_trade(SecurityData* data, const onixs::PRICE& price, int size, AggressorSide agside, const onixs::Timestamp& onixs_date) {
|
||||
auto ts = utils::TimeStamp::now();
|
||||
PriceSize ps = pricesize_of_price_size(price, data->handle.security().display_factor, size);
|
||||
auto date = ll_of_timestamp(onixs_date);
|
||||
data->handle.add_trade(ts, ps, date, data->electronic_volume + size);
|
||||
data->handle.add_trade(ts, ps, date, agside, data->electronic_volume + size);
|
||||
}
|
||||
|
||||
void MDP3Listener::onTrade(onixs::Handler&, const onixs::Security& sec, const onixs::RecoveryEntryArgs& arg) {
|
||||
@@ -364,7 +377,7 @@ void MDP3Listener::onTrade(onixs::Handler&, const onixs::Security& sec, const on
|
||||
arg.entry().entrySize(size);
|
||||
onixs::PRICE price;
|
||||
arg.entry().entryPx(price);
|
||||
on_trade(data, price, size, arg.message().transactTime());
|
||||
on_trade(data, price, size, AGGRESSOR_SIDE_NONE, arg.message().transactTime());
|
||||
}
|
||||
}
|
||||
void MDP3Listener::onTrade(onixs::Handler&, const onixs::Security& sec, const onixs::TradeSummaryArgs& arg) {
|
||||
@@ -373,7 +386,9 @@ void MDP3Listener::onTrade(onixs::Handler&, const onixs::Security& sec, const on
|
||||
if (data != NULL) {
|
||||
auto size = arg.entry().entrySize();
|
||||
onixs::PRICE price = arg.entry().entryPx();
|
||||
on_trade(data, price, size, arg.message().transactTime());
|
||||
onixs::AggressorSide::Enum agside = onixs::AggressorSide::NoAggressor;
|
||||
arg.entry().aggressorSide(agside);
|
||||
on_trade(data, price, size, map_aggressor(agside), arg.message().transactTime());
|
||||
}
|
||||
}
|
||||
void MDP3Listener::onTrade(onixs::Handler&, const onixs::Security& sec, const onixs::TradeArgs& arg) {
|
||||
@@ -383,7 +398,9 @@ void MDP3Listener::onTrade(onixs::Handler&, const onixs::Security& sec, const on
|
||||
if (data != nullptr) {
|
||||
int size = arg.entry().entrySize();
|
||||
onixs::PRICE price = arg.entry().entryPx();
|
||||
on_trade(data, price, size, arg.message().transactTime());
|
||||
onixs::AggressorSide::Enum agside = onixs::AggressorSide::NoAggressor;
|
||||
arg.entry().aggressorSide(agside);
|
||||
on_trade(data, price, size, map_aggressor(agside), arg.message().transactTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,9 +218,14 @@ void ExecutionGateway::on_exe_report(
|
||||
: api::orderman::MANUAL_ORDER_INDICATOR_YES;
|
||||
str_to(msg.get<fix::OrderID>(), &data->exchange_order_id);
|
||||
|
||||
if (msg.has<fix::Price>())
|
||||
data->price = securities::decode_exchange_price(
|
||||
*sec, Price(msg.get<fix::Price>()));
|
||||
if (msg.has<fix::Price>()) {
|
||||
if (data->leg_security)
|
||||
data->price = securities::decode_exchange_price(
|
||||
*data->leg_security, Price(msg.get<fix::Price>()));
|
||||
else
|
||||
data->price = securities::decode_exchange_price(
|
||||
*sec, Price(msg.get<fix::Price>()));
|
||||
}
|
||||
else
|
||||
data->price = Price(os::nan());
|
||||
|
||||
|
||||
@@ -271,9 +271,17 @@ void IcebergOrder::on_child_order_update(OrderStateUpdateEvent const &ev) {
|
||||
break;
|
||||
}
|
||||
|
||||
case ORDER_STATUS_CANCELED:
|
||||
LOG(OrderMan, Info,
|
||||
"Unexpected cancel of child {} in Iceberg Order {}. Canceling "
|
||||
"parent",
|
||||
ev.key.value(),
|
||||
key().value());
|
||||
transition(ORDER_STATUS_CANCELED);
|
||||
break;
|
||||
|
||||
case ORDER_STATUS_DISCONNECTED:
|
||||
case ORDER_STATUS_REJECTED_BY_SPARK:
|
||||
case ORDER_STATUS_CANCELED:
|
||||
case ORDER_STATUS_ERROR:
|
||||
me->child.clear();
|
||||
transition(ORDER_STATUS_ERROR, "Unexpected child order state");
|
||||
|
||||
@@ -588,6 +588,12 @@ void NativeOrder::on_exe_report(const NewExecutionReportEvent &er) {
|
||||
auto &state = me->state;
|
||||
auto &native_state = get_native_state(state);
|
||||
|
||||
if (er.data->leg_security) {
|
||||
LOG(OrderMan, Diag,
|
||||
"Ignoring leg execution report for order {}", key().value());
|
||||
return;
|
||||
}
|
||||
|
||||
if (native_state.last_msg_seq_num() > er.data->msg_seq_num) {
|
||||
LOG(OrderMan, Warn,
|
||||
"Ignoring already seen execution report {} in order {}",
|
||||
|
||||
@@ -139,7 +139,7 @@ body {
|
||||
.is-main-control-bar {
|
||||
margin:2rem 3rem 0 0;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
//text-align: center;
|
||||
.button {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ let init (context:ServiceContext.ServiceContext) =
|
||||
mdRelayExpNameData = Array.empty<ExpirationNameList>
|
||||
scratch = emptyAccount
|
||||
previousScratch = emptyAccount
|
||||
AllValue = ""
|
||||
AllValueDisplay = ""
|
||||
AllValue = "*"
|
||||
AllValueDisplay = "All"
|
||||
OptionsMenuOpen = ""
|
||||
ConfirmModal = "", (Msg.SelectTab General)
|
||||
SelectedClipLimits = []
|
||||
|
||||
@@ -69,10 +69,12 @@ let GetSymbolArray (model:Model) =
|
||||
|> Array.distinct
|
||||
|
||||
let GetFilteredSymbolArray (model:Model) (remove:string []) =
|
||||
Array.map<bts.api.Product, string> (fun a -> a.symbol ) model.mdRelayProductData
|
||||
|> Array.filter (fun elm -> (not <| Array.exists (fun e -> elm = e) remove))
|
||||
|> Array.distinct
|
||||
|
||||
let a = (Array.map<bts.api.Product, string> (fun a -> a.symbol ) model.mdRelayProductData
|
||||
|> Array.filter (fun elm -> (not <| Array.exists (fun e -> elm = e) remove))
|
||||
|> Array.distinct)
|
||||
match a.Length with
|
||||
| 0 -> a
|
||||
| _ -> [ a; [|model.AllValueDisplay|] ] |> Array.concat
|
||||
|
||||
let limitFilter (positionLimit:AccountSecurityPositionLimitUnit option) (clipLimit:AccountSecurityClipLimitUnit option) allValueDisplay (array:'a []) =
|
||||
match positionLimit, clipLimit with
|
||||
@@ -193,7 +195,11 @@ let clipLimitsView model dispatch =
|
||||
&& (elm.security.securityType = limit.security.securityType)
|
||||
)
|
||||
model.scratch.securityClipLimits.limit
|
||||
|> Array.map (fun (elm:AccountSecurityClipLimitUnit) -> elm.security.securitySymbol)
|
||||
|> Array.map (fun (elm:AccountSecurityClipLimitUnit) ->
|
||||
match (elm.security.securitySymbol = model.AllValue) with
|
||||
| true -> model.AllValueDisplay
|
||||
| false -> elm.security.securitySymbol
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -223,7 +229,7 @@ let clipLimitsView model dispatch =
|
||||
)
|
||||
TableControl.Cell (Fields.enumSelect<string>
|
||||
""
|
||||
limit.security.securitySymbol
|
||||
(match (limit.security.securitySymbol = model.AllValue) with | true -> model.AllValueDisplay | false -> limit.security.securitySymbol)
|
||||
(GetFilteredSymbolArray model <| (getUsedSymbolNames limit))
|
||||
[]
|
||||
(fun value -> ((limit, (changeSymbol limit value)) |> ClipLimits |> dispatch))
|
||||
@@ -262,7 +268,7 @@ let clipLimitsView model dispatch =
|
||||
div [ ClassName "column is-size-7 has-text-grey-mid is-help-text"; ]
|
||||
[str "Clip limits can be set for one security, for all securities in a product (by selecting \"All\" for securities), or for all products within a security type (by selecting \"All\" for both symbol and security)"]
|
||||
]
|
||||
TableControl.createDataTable (Some headerRow) rws (Button.button "Add" "" "plus" Button.Enabled addRow)
|
||||
TableControl.createDataTable (Some headerRow) rws (Button.button "Add" "" "plus-circle" Button.Enabled addRow)
|
||||
]
|
||||
|
||||
let productLimits model dispatch =
|
||||
@@ -362,7 +368,11 @@ let productLimits model dispatch =
|
||||
&& (elm.product.securityType = limit.product.securityType)
|
||||
)
|
||||
model.scratch.productPositionLimits
|
||||
|> Array.map (fun (elm:AccountProductPositionLimitUnit) -> elm.product.securitySymbol)
|
||||
|> Array.map (fun (elm:AccountProductPositionLimitUnit) ->
|
||||
match (elm.product.securitySymbol = model.AllValue) with
|
||||
| true -> model.AllValueDisplay
|
||||
| false -> elm.product.securitySymbol
|
||||
)
|
||||
|
||||
|
||||
let rws:TableControl.row list =
|
||||
@@ -390,7 +400,7 @@ let productLimits model dispatch =
|
||||
)
|
||||
TableControl.Cell (Fields.enumSelect<string>
|
||||
""
|
||||
limit.product.securitySymbol
|
||||
(match (limit.product.securitySymbol = model.AllValue) with | true -> model.AllValueDisplay | false -> limit.product.securitySymbol)
|
||||
(GetFilteredSymbolArray model (getUsedSymbolNames limit))
|
||||
[]
|
||||
(fun value -> ((limit, (changeSymbol limit value)) |> ProductLimits |> dispatch))
|
||||
@@ -433,7 +443,7 @@ let productLimits model dispatch =
|
||||
div [ ClassName "column is-size-7 has-text-grey-mid is-help-text" ]
|
||||
[str "This limits the net position for a product (i.e. accumulated position over all securities belonging to a product). This can be set for one product, or for all products within a security type by selecting \"All\" for symbol"]
|
||||
]
|
||||
TableControl.createDataTable (Some headerRow) rws (Button.button "Add" "" "plus" Button.Enabled addRow)
|
||||
TableControl.createDataTable (Some headerRow) rws (Button.button "Add" "" "plus-circle" Button.Enabled addRow)
|
||||
br []
|
||||
]
|
||||
|
||||
@@ -551,7 +561,7 @@ let securityLimitsView model dispatch =
|
||||
div [ ClassName "column is-size-7 has-text-grey-mid is-help-text" ]
|
||||
[str "Optionally, the net position for one or more securities can also be limited. For example, the Product Limits can be set to restrict the Max Net Long Position across all ES futures to 10,000 contracts, but Security Limits can be used to restrict the ES Jun future to 500 only"]
|
||||
]
|
||||
TableControl.createDataTable (Some headerRow) rws (Button.button "Add" "" "plus" Button.Enabled addRow)
|
||||
TableControl.createDataTable (Some headerRow) rws (Button.button "Add" "" "plus-circle" Button.Enabled addRow)
|
||||
]
|
||||
|
||||
let LimitsView model dispatch =
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
$known_good = @{
|
||||
"6A" = 1000
|
||||
"6B" = 625
|
||||
"6D" = 1000
|
||||
"6E" = 1250
|
||||
"6J" = 1250
|
||||
"CL" = 1000
|
||||
"EMD" = 100
|
||||
"ES" = 50
|
||||
"GC" = 100
|
||||
"GE" = 2500
|
||||
"HE" = 400
|
||||
"HG" = 5000
|
||||
"HO" = 42000
|
||||
"LE" = 400
|
||||
"M6E" = 125
|
||||
"NG" = 100
|
||||
"NQ" = 20
|
||||
"QM" = 500
|
||||
"RB" = 42000
|
||||
"RTY" = 50
|
||||
"SI" = 5000
|
||||
"VX" = 1000
|
||||
"YI" = 10
|
||||
"YM" = 5
|
||||
"ZB" = 1000
|
||||
"ZC" = 50
|
||||
"ZF" = 1000
|
||||
"ZL" = 600
|
||||
"ZM" = 100
|
||||
"ZN" = 1000
|
||||
"ZQ" = 4167
|
||||
"ZS" = 50
|
||||
"ZT" = 2000
|
||||
"ZW" = 50
|
||||
}
|
||||
@@ -1,43 +1,9 @@
|
||||
$known_good = @{
|
||||
"6A" = 1000
|
||||
"6B" = 625
|
||||
"6D" = 1000
|
||||
"6E" = 1250
|
||||
"6J" = 1250
|
||||
"M6E" = 125
|
||||
"NQ" = 20
|
||||
"ES" = 50
|
||||
"YM" = 5
|
||||
"RTY" = 50
|
||||
"VX" = 1000
|
||||
"EMD" = 100
|
||||
"GE" = 2500
|
||||
"ZB" = 1000
|
||||
"ZN" = 1000
|
||||
"ZF" = 1000
|
||||
"ZT" = 2000
|
||||
"ZQ" = 4167
|
||||
"SI" = 50
|
||||
"YI" = 10
|
||||
"GC" = 100
|
||||
"HG" = 250
|
||||
"CL" = 1000
|
||||
"NG" = 100
|
||||
"HO" = 420
|
||||
"QM" = 500
|
||||
"RB" = 420
|
||||
"ZC" = 50
|
||||
"ZS" = 50
|
||||
"ZW" = 50
|
||||
"LE" = 400
|
||||
"HE" = 400
|
||||
"ZM" = 100
|
||||
"ZL" = 600
|
||||
}
|
||||
# Dot sourcing the reqs file will make
|
||||
. .\Generate-Cpps-reqs.ps1
|
||||
|
||||
$cme_file_url = "ftp://ftp.cmegroup.com/pub/fprf/csv/cmeg.fut.prf.csv"
|
||||
$csv_save_path = ".\cmeg.fut.prf.csv"
|
||||
$output_file = ".\cpp_out.txt"
|
||||
$output_file = ".\cpp_config.conf"
|
||||
|
||||
# turn off console update progress while downloading
|
||||
$CurrentProgressPref = $ProgressPreference;
|
||||
@@ -47,11 +13,23 @@ $ProgressPreference = $CurrentProgressPref
|
||||
|
||||
$a = Import-Csv $csv_save_path
|
||||
$b = $a | select Sym, Mult | Group Sym | Sort Name
|
||||
|
||||
@"
|
||||
# Generated by automated script. DO NOT EDIT!
|
||||
# source: tools/cpp_helper/generate-cpps.ps1
|
||||
"@ | out-file -Encoding ascii $output_file
|
||||
"CppConfig`n{`n`tvalue`n`t{" | out-file -Encoding ascii $output_file -Append
|
||||
$b | % {
|
||||
if ($known_good.ContainsKey($_.Group[0].Sym)) {
|
||||
$cpp = $known_good[$_.Group[0].Sym]
|
||||
} else {
|
||||
$cpp = $_.Group[0].Mult
|
||||
}
|
||||
"cpp_entry {{ `n`tkey: `"{0}`"`n`tvalue: {1}`n}}" -f $_.Group[0].Sym, $cpp } `
|
||||
| out-file -Encoding ascii $output_file
|
||||
"`t`tcpp_entry {{ key: `"{0}`" value: {1} }}" -f $_.Group[0].Sym, $cpp } `
|
||||
| out-file -Encoding ascii $output_file -Append
|
||||
"`t}`n}" | out-file -Encoding ascii $output_file -Append
|
||||
Remove-Item $csv_save_path -Force
|
||||
|
||||
# You can now copy the output file to defaults assuming all looks good
|
||||
# Copy-Item .\cpp_config.conf ..\..\src\lib\config\defaults\ -Force
|
||||
# Remove-Item cpp-config.conf
|
||||
Reference in new issue
Block a user