Compare commits
142
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc3353e243 | ||
|
|
683b85c66b | ||
|
|
789710d841 | ||
|
|
41bc4f7950 | ||
|
|
963bd15b35 | ||
|
|
282e10cba3 | ||
|
|
fa1b436fb3 | ||
|
|
1a9ff09f43 | ||
|
|
191518d8bc | ||
|
|
50768750d6 | ||
|
|
450ef7dd56 | ||
|
|
89a4f9264a | ||
|
|
55ade15574 | ||
|
|
36b8b35e47 | ||
|
|
23bb872052 | ||
|
|
13b09ffc12 | ||
|
|
83a2a01789 | ||
|
|
e1137c4e1d | ||
|
|
bf8df1d396 | ||
|
|
d064af817c | ||
|
|
7b3c4b76bc | ||
|
|
5de431f279 | ||
|
|
7b63d951f0 | ||
|
|
018887980b | ||
|
|
8b4d649bd4 | ||
|
|
441d3c886b | ||
|
|
472e32f558 | ||
|
|
472c9252f9 | ||
|
|
98a9ad3ef2 | ||
|
|
7b237fedea | ||
|
|
7281aa8ff1 | ||
|
|
d915e2f064 | ||
|
|
beb5d855b1 | ||
|
|
120b86aaae | ||
|
|
44eeff98e7 | ||
|
|
dc420a097a | ||
|
|
69ee85dea9 | ||
|
|
0a6cc0cdf1 | ||
|
|
e96d9112ef | ||
|
|
72aa028bd6 | ||
|
|
f8d5b9bace | ||
|
|
e861e2916f | ||
|
|
23738b109d | ||
|
|
713e11d146 | ||
|
|
444e3154b3 | ||
|
|
270ee60df9 | ||
|
|
1ce041c5e5 | ||
|
|
50940bfd13 | ||
|
|
8cb4151f63 | ||
|
|
7a47b7a85a | ||
|
|
a60a792dfa | ||
|
|
a73a1cc4f5 | ||
|
|
32fbdf8a21 | ||
|
|
75c54bbe3e | ||
|
|
38575039b9 | ||
|
|
43a49b9399 | ||
|
|
618c41ce97 | ||
|
|
bd8c9c354b | ||
|
|
8f5d062a3b | ||
|
|
e1a3950051 | ||
|
|
7e816c1503 | ||
|
|
15d9afb2de | ||
|
|
b5468e5565 | ||
|
|
a4c3a61f13 | ||
|
|
7ce101f7f7 | ||
|
|
b61cab397d | ||
|
|
222e1a51dc | ||
|
|
9fa3464188 | ||
|
|
fee695d3d9 | ||
|
|
140f1d88ea | ||
|
|
c4eeaf2ec8 | ||
|
|
54dd30245f | ||
|
|
263ff63a37 | ||
|
|
f3d16502de | ||
|
|
4b7db298c4 | ||
|
|
65f41452fb | ||
|
|
d7a2ae4b09 | ||
|
|
61ac626542 | ||
|
|
8d7a2f342e | ||
|
|
0db037175f | ||
|
|
98aa463b4e | ||
|
|
0b40d3971d | ||
|
|
a21a769909 | ||
|
|
ca8e540453 | ||
|
|
134950747f | ||
|
|
5abc17adf3 | ||
|
|
f3cd3a402e | ||
|
|
c7217b8475 | ||
|
|
99c5129ea7 | ||
|
|
d025ee0c89 | ||
|
|
c24ddaa190 | ||
|
|
442aa156ac | ||
|
|
e906d41cc2 | ||
|
|
6e09d9e949 | ||
|
|
aea02e212a | ||
|
|
a94a66234a | ||
|
|
4cbbf6972a | ||
|
|
caa9671c96 | ||
|
|
20eb3ed39d | ||
|
|
772a898433 | ||
|
|
b5997d326e | ||
|
|
f8626f81cd | ||
|
|
bc208d2421 | ||
|
|
625ebcc762 | ||
|
|
0a163badf0 | ||
|
|
dea95455a0 | ||
|
|
f0f5988abf | ||
|
|
db5f16985c | ||
|
|
f0105867be | ||
|
|
2c0b314428 | ||
|
|
3cd74f33f1 | ||
|
|
a6ee36f4bc | ||
|
|
9cadf635fb | ||
|
|
43e043b044 | ||
|
|
6bac75d7ab | ||
|
|
7ceb170c5f | ||
|
|
47c7ee71b4 | ||
|
|
4f58452771 | ||
|
|
d5bf15cc36 | ||
|
|
9736541385 | ||
|
|
5591c8316d | ||
|
|
a44d3a2c26 | ||
|
|
dceb300324 | ||
|
|
84b9ca3096 | ||
|
|
17e9f1ea96 | ||
|
|
946ec36840 | ||
|
|
11425a898f | ||
|
|
d0029e7f88 | ||
|
|
bdbdda947f | ||
|
|
f88ab57fa0 | ||
|
|
36442a037e | ||
|
|
5969568dee | ||
|
|
96265ea187 | ||
|
|
9676b1fdca | ||
|
|
556132c2dd | ||
|
|
a22b7b7189 | ||
|
|
8e41a42ced | ||
|
|
e0f7bdfc13 | ||
|
|
ec0b96215f | ||
|
|
e27a8be526 | ||
|
|
70cd9f185e | ||
|
|
33eaf6f86d |
No files matched your search
@@ -16,6 +16,7 @@ insert_anchor_links = "right"
|
||||
selected by default
|
||||
- Increased width of login panel to better show login error messages
|
||||
- Added optional 'Maker/Taker' pricing to Spreader algo
|
||||
- Algo buttons in ladder can now be made to deactivate after launching an algo or remain 'sticky'
|
||||
### Internal changes
|
||||
- Made it easier to generate simple UI's for new order types
|
||||
### API Changes
|
||||
|
||||
+1
-1
Submodule docker/linux updated: e13bb5d8df...b09d4c035b.
+1
-1
Submodule externals updated: 67a79263ba...6b8c745fb2.
@@ -26,6 +26,7 @@ namespace mbts.spark {
|
||||
readonly ObservableFilterCollection<OrderRecordImmutable> _working_orders, _working_bids, _working_asks;
|
||||
readonly string _security_text, _security_key_text;
|
||||
readonly Property<double> _bid_price, _ask_price, _last_price, _day_change, _settlement, _session_high, _session_low;
|
||||
readonly Property<bool> _last_price_from_spread;
|
||||
readonly CellProperty<int> _position;
|
||||
readonly CellProperty<uint> _last_size;
|
||||
readonly CellProperty<ulong> _volume;
|
||||
@@ -53,6 +54,7 @@ namespace mbts.spark {
|
||||
_day_change = backing(nameof(day_change), double.NaN);
|
||||
_session_low = backing(nameof(session_low), double.NaN);
|
||||
_session_high = backing(nameof(session_high), double.NaN);
|
||||
_last_price_from_spread = backing(nameof(last_price_from_spread), false);
|
||||
_settlement = backing(nameof(settlement), double.NaN);
|
||||
_volume = new CellProperty<ulong>(this, nameof(volume), 0);
|
||||
_inside_bids = new CellProperty<bool>(this, nameof(inside_bids));
|
||||
@@ -103,6 +105,7 @@ namespace mbts.spark {
|
||||
public bool inside_asks => _inside_asks.value;
|
||||
public int position => _position.value;
|
||||
public double last_price => _last_price.Value;
|
||||
public bool last_price_from_spread => _last_price_from_spread.Value;
|
||||
public uint last_size => _last_size.value;
|
||||
public double bid_price => _bid_price.Value;
|
||||
public uint bid_direct_size => _bid_direct_size.Value;
|
||||
@@ -161,15 +164,17 @@ namespace mbts.spark {
|
||||
_inside_bids.on_next_distinct(_bid_price.Value >= _working_best_bid.value, ref dirty);
|
||||
_inside_asks.on_next_distinct(_ask_price.Value <= _working_best_ask.value, ref dirty);
|
||||
}
|
||||
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v)) {
|
||||
if (md.md.get_last_trade(ref _last_ref, out NativePriceSize ps, out DateTime ts, out ulong v, out bool from_spread)) {
|
||||
_last_price.set(ps.price);
|
||||
_last_price_from_spread.set(from_spread);
|
||||
_last_size.on_next_distinct(ps.size, ref dirty);
|
||||
_volume.on_next_distinct(v, ref dirty);
|
||||
}
|
||||
_settlement.set(md.md.settlement_price);
|
||||
_session_low.set(md.md.session_low);
|
||||
_session_high.set(md.md.session_high);
|
||||
_day_change.set(last_price - settlement);
|
||||
dirty |= _settlement.set_new(md.md.settlement_price);
|
||||
dirty |= _session_low.set_new(md.md.session_low);
|
||||
dirty |= _session_high.set_new(md.md.session_high);
|
||||
dirty |= _day_change.set_new(last_price - settlement);
|
||||
_volume.on_next_distinct(md.md.total_volume, ref dirty);
|
||||
if (dirty)
|
||||
invalidated?.Invoke();
|
||||
|
||||
|
||||
@@ -39,7 +39,8 @@ namespace mbts.spark {
|
||||
IMultiValueConverter price_converter = new ui.spark.converters.TickDisplayConverter();
|
||||
add_col(Columns.Security, "Security", r => r.security.ToString(), nameof(Row.security), DefaultColumnWidths.Security, security_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.Volume, "Volume", r => r.volume.ToString(), nameof(Row.volume), DefaultColumnWidths.Volume, volume_filter, DataGridFilterKnownTemplates.ULongMinMax);
|
||||
add_col(Columns.Last, "Last", r => r.format_price(r.last_price), nameof(Row.last_price), DefaultColumnWidths.Price, last_price_filter, DataGridFilterKnownTemplates.DoubleMinMax);
|
||||
add_col(Columns.LastSpd, "Spd", r => r.last_price_from_spread ? "S" : "", nameof(Row.last_price_from_spread), DefaultColumnWidths.Side, last_price_from_spread_filter, DataGridFilterKnownTemplates.Regex);
|
||||
add_col(Columns.Last, "Last", r => r.format_price(r.last_price), nameof(Row.last_price), DefaultColumnWidths.Price, last_price_filter, DataGridFilterKnownTemplates.DoubleMinMax);
|
||||
add_col(Columns.LastSize, merged_size_col_header, r => r.last_size.ToString(), nameof(Row.last_size), DefaultColumnWidths.Size, last_size_filter, DataGridFilterKnownTemplates.UIntMinMax, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_col(Columns.Position, "Pos", r => r.position.ToString(), nameof(Row.position), DefaultColumnWidths.Size, position_filter, DataGridFilterKnownTemplates.IntMinMax, true, h_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
add_hl_working_orders_col(Columns.WorkingBids, working_col_header, nameof(Row.working_bids_text), nameof(Row.working_best_bid), nameof(Row.working_bids_click), working_bid_volume_filter, BTSColors.MarketData.bid, System.Windows.HorizontalAlignment.Right);
|
||||
@@ -145,6 +146,7 @@ namespace mbts.spark {
|
||||
ask_direct_size_filter.load_state(filters.ask_direct_size);
|
||||
ask_implied_size_filter.load_state(filters.ask_implied_size);
|
||||
last_price_filter.load_state(filters.last_price);
|
||||
last_price_from_spread_filter.load_state(filters.last_price_from_spread);
|
||||
last_size_filter.load_state(filters.last_size);
|
||||
day_change_filter.load_state(filters.day_change);
|
||||
settlement_filter.load_state(filters.settlement);
|
||||
@@ -161,7 +163,7 @@ namespace mbts.spark {
|
||||
}), DataGridFilterHelper.hook_filters(rows_view, security_filter,
|
||||
bid_price_filter, bid_merged_size_filter, bid_direct_size_filter, bid_implied_size_filter,
|
||||
ask_price_filter, ask_merged_size_filter, ask_direct_size_filter, ask_implied_size_filter,
|
||||
last_price_filter, last_size_filter, day_change_filter, settlement_filter,
|
||||
last_price_filter, last_price_from_spread_filter, last_size_filter, day_change_filter, settlement_filter,
|
||||
session_low_filter, session_high_filter, position_filter, working_bid_volume_filter, working_ask_volume_filter, volume_filter, security_key_filter),
|
||||
settings_manager.subscribe_current().OnDispatcher().Subscribe(grid_settings_manager),
|
||||
WorkLoop.Start("MarketView", _refresh)
|
||||
@@ -224,6 +226,7 @@ namespace mbts.spark {
|
||||
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> ask_direct_size_filter { get; } = new UIntMinMax<Row>(r => r.ask_direct_size, nameof(Row.ask_direct_size));
|
||||
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> ask_implied_size_filter { get; } = new UIntMinMax<Row>(r => r.ask_implied_size, nameof(Row.ask_implied_size));
|
||||
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> last_price_filter { get; } = new DoubleMinMax<Row>(r => r.last_price, nameof(Row.last_price));
|
||||
public IDataGridColumnPersistentFilter<Row, string> last_price_from_spread_filter { get; } = new RegexFilterVM<Row>(r => r.last_price_from_spread.ToString(), nameof(Row.last_price_from_spread));
|
||||
public IDataGridColumnPersistentFilter<Row, UIntMinMaxState> last_size_filter { get; } = new UIntMinMax<Row>(r => r.last_size, nameof(Row.last_size));
|
||||
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> day_change_filter { get; } = new DoubleMinMax<Row>(r => r.day_change, nameof(Row.day_change));
|
||||
public IDataGridColumnPersistentFilter<Row, DoubleMinMaxState> settlement_filter { get; } = new DoubleMinMax<Row>(r => r.settlement, nameof(Row.settlement));
|
||||
@@ -255,6 +258,7 @@ namespace mbts.spark {
|
||||
ask_direct_size = ask_direct_size_filter.get_state(),
|
||||
ask_implied_size = ask_implied_size_filter.get_state(),
|
||||
last_price = last_price_filter.get_state(),
|
||||
last_price_from_spread = last_price_from_spread_filter.get_state(),
|
||||
last_size = last_size_filter.get_state(),
|
||||
day_change = day_change_filter.get_state(),
|
||||
settlement = settlement_filter.get_state(),
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace mbts.ui.spark {
|
||||
/// Interaction logic for MarketSheetsView.xaml
|
||||
/// </summary>
|
||||
partial class MarketViewView : UserControl {
|
||||
public enum Columns { Security, Volume, Last, LastSize, Position, WorkingBids, Bid, BidMergedSize, BidDirectSize, BidImpliedSize, Ask, AskMergedSize, AskDirectSize, AskImpliedSize, WorkingAsks, Settlement, DayChange, SessionLow, SessionHigh, SecurityKey,
|
||||
public enum Columns { Security, Volume, Last, LastSpd, LastSize, Position, WorkingBids, Bid, BidMergedSize, BidDirectSize, BidImpliedSize, Ask, AskMergedSize, AskDirectSize, AskImpliedSize, WorkingAsks, Settlement, DayChange, SessionLow, SessionHigh, SecurityKey,
|
||||
MarketDescription, ClearedAlias, ProductDescription, HubAlias, StripName, MicCode
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ namespace bts.shell {
|
||||
public static GridColumnSettings security => new GridColumnSettings(col_id(Columns.Security), DefaultColumnHeaders.Security, width: DefaultColumnWidths.Security);
|
||||
public static GridColumnSettings volume => new GridColumnSettings(col_id(Columns.Volume), DefaultColumnHeaders.Volume, width: DefaultColumnWidths.Volume);
|
||||
public static GridColumnSettings last => new GridColumnSettings(col_id(Columns.Last), DefaultColumnHeaders.Last, width: DefaultColumnWidths.Price);
|
||||
public static GridColumnSettings last_from_spread => new GridColumnSettings(col_id(Columns.LastSpd), DefaultColumnHeaders.S, width: DefaultColumnWidths.Price, is_visible: false);
|
||||
public static GridColumnSettings last_size => new GridColumnSettings(col_id(Columns.LastSize), DefaultColumnHeaders.Size, width: DefaultColumnWidths.Size, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings position => new GridColumnSettings(col_id(Columns.Position), DefaultColumnHeaders.Pos, width: DefaultColumnWidths.Size, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
public static GridColumnSettings working_bids => new GridColumnSettings(col_id(Columns.WorkingBids), DefaultColumnHeaders.Working, font_color_override: BTSColors.MarketData.bid, width: DefaultColumnWidths.Working, horizontal_alignment: System.Windows.HorizontalAlignment.Right);
|
||||
@@ -117,6 +118,7 @@ namespace bts.shell {
|
||||
yield return security;
|
||||
yield return volume;
|
||||
yield return last;
|
||||
yield return last_from_spread;
|
||||
yield return last_size;
|
||||
yield return position;
|
||||
yield return working_bids;
|
||||
@@ -200,6 +202,8 @@ namespace bts.shell {
|
||||
[ProtoMember(25)]
|
||||
public string strip_name;
|
||||
[ProtoMember(26)]
|
||||
public string last_price_from_spread;
|
||||
[ProtoMember(27)]
|
||||
public string mic_code;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ using System.Reactive.Disposables;
|
||||
namespace mbts.spark {
|
||||
static class AlgoParamRowsHelper {
|
||||
public static IDisposable connect(AlgoDefinitionVM algo, ObservableAggregateCollection<AlgoParamRowVM> rows, bool include_algo_type_rows) =>
|
||||
algo == null ? null : new CompositeDisposable(algo.observe_algo_root().SubscribeEach(a => {
|
||||
algo == null ? null : new CompositeDisposable(algo.observe_algo_root().OnDispatcher().SubscribeEach(a => {
|
||||
rows.clear_collections();
|
||||
if (a == null)
|
||||
return Disposable.empty;
|
||||
@@ -77,7 +77,7 @@ namespace mbts.spark {
|
||||
include_algo_type_rows ?
|
||||
(ObservableCollection<AlgoParamRowVM>)new ObservableAppendCollection<AlgoParamRowVM>(child_rows, selector_wrapper) :
|
||||
child_rows,
|
||||
s.subscribe_selected_algo().SubscribeEach(a => {
|
||||
s.subscribe_selected_algo().OnDispatcher().SubscribeEach(a => {
|
||||
s.value = a;
|
||||
child_rows.clear_collections();
|
||||
return _wrap_rows(a, selector_wrapper, child_rows, include_algo_type_rows);
|
||||
|
||||
@@ -87,6 +87,7 @@ namespace mbts.spark {
|
||||
add_col(Columns.Size, DefaultColumnHeaders.Size, r => r.size.ToString(), new DoubleMinMax<FillTuple>(r => r.fill.LastShares), DataGridFilterKnownTemplates.UIntMinMax, DefaultColumnWidths.Size);
|
||||
add_col(Columns.Price, DefaultColumnHeaders.Price, r => r.format_price(r.price), new DoubleMinMax<FillTuple>(r => r.fill.LastPrice), DataGridFilterKnownTemplates.DoubleMinMax, DefaultColumnWidths.Price);
|
||||
add_col(Columns.FillKind, DefaultColumnHeaders.FillKind, r => r.fill_kind.ToString(), dv_filter(EnumHelper.get_values<FillKind>().ToArray(), r => r.fill.FillKind), DataGridFilterKnownTemplates.DiscreteValues, DefaultColumnWidths.FillKind);
|
||||
add_col(Columns.FillStatus, DefaultColumnHeaders.FillStatus, r => r.fill_status.ToString(), dv_filter(EnumHelper.get_values<FillStatus>().ToArray(), r => r.fill.FillStatus), DataGridFilterKnownTemplates.DiscreteValues, DefaultColumnWidths.FillKind);
|
||||
add_col(Columns.FillKey, DefaultColumnHeaders.FillKey, r => r.fill_key.ToString(), new RegexFilterVM<FillTuple>(r => r.fill.FillKey), DataGridFilterKnownTemplates.Regex, DefaultColumnWidths.FillKey);
|
||||
add_col(Columns.OrderKey, DefaultColumnHeaders.OrderKey, r => r.order_key.ToString(), new RegexFilterVM<FillTuple>(r => r.fill.OrderKey.ToString()), DataGridFilterKnownTemplates.Regex, DefaultColumnWidths.OrderKey);
|
||||
add_col(Columns.SecurityKey, DefaultColumnHeaders.SecurityKey, r => r.security_key.ToString(), new RegexFilterVM<FillTuple>(r => r.fill.SecurityKey.ToString()), DataGridFilterKnownTemplates.Regex, DefaultColumnWidths.SecurityKey);
|
||||
@@ -188,6 +189,7 @@ namespace mbts.spark {
|
||||
case Columns.Exchange: return wrap_default(ft => ft.security.exchange_or_default());
|
||||
case Columns.FillKey: return wrap(ft => ft.fill.FillKey);
|
||||
case Columns.FillKind: return wrap_default(ft => ft.fill.FillKind);
|
||||
case Columns.FillStatus: return wrap_default(ft => ft.fill.FillStatus);
|
||||
case Columns.FillTime: return wrap(ft => ft.fill.Timestamp.to_local_time());
|
||||
case Columns.OrderKey: return wrap(ft => ft.fill.OrderKey);
|
||||
case Columns.OrderType: return wrap_default(ft => ft.order?.order_type() ?? OrderType.None);
|
||||
@@ -249,6 +251,7 @@ namespace mbts.spark {
|
||||
public double price => _fill.LastPrice;
|
||||
public double size => _fill.LastShares;
|
||||
public FillKind fill_kind => _fill.FillKind;
|
||||
public FillStatus fill_status => _fill.FillStatus;
|
||||
public string fill_key => _fill.FillKey;
|
||||
public string order_key => _order.Key.ToString();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace mbts.ui.spark {
|
||||
Price,
|
||||
Size,
|
||||
FillKind,
|
||||
FillStatus,
|
||||
FillKey,
|
||||
OrderKey,
|
||||
SecurityKey
|
||||
|
||||
@@ -67,5 +67,8 @@ namespace bts.shell {
|
||||
set: (us, gs) => us.with(provided_fills_gridsettings: gs));
|
||||
return new FillsWindow(this, _bus, _orders_model, state, settings_manager);
|
||||
}
|
||||
[ProtoMember(15)]
|
||||
[DIYGridColumnID(nameof(Columns.FillStatus))]
|
||||
public Fill.Types.FillStatus[] fill_status { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,10 @@ namespace bts.shell.fills {
|
||||
[ProtoMember(15)]
|
||||
[DIYGridColumnID(nameof(Columns.Symbol))]
|
||||
public string[] symbol { get; set; }
|
||||
|
||||
[ProtoMember(16)]
|
||||
[DIYGridColumnID(nameof(Columns.FillStatus))]
|
||||
public Fill.Types.FillStatus[] fill_status { get; set; }
|
||||
}
|
||||
|
||||
static class FillsFilterStatesExtensions {
|
||||
@@ -91,6 +95,7 @@ namespace bts.shell.fills {
|
||||
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);
|
||||
pb.add_discrete_values(fs.fill_status, ft => ft.fill.FillStatus);
|
||||
// numeric
|
||||
pb.add_numeric(fs.size, ft => ft.fill.LastShares);
|
||||
pb.add_numeric(fs.price, ft => ft.fill.LastPrice);
|
||||
|
||||
@@ -194,20 +194,27 @@ namespace mbts.spark {
|
||||
readonly bts.persist.algo.AlgoPersistedKey[] _favorite_algos;
|
||||
[ProtoMember(2)]
|
||||
public readonly int column_count;
|
||||
[ProtoMember(3)]
|
||||
readonly bts.persist.algo.AlgoPersistedKey[] _stickied_algos;
|
||||
|
||||
public LadderFavoriteAlgosSettings(AlgoKey[] favorite_algos, int column_count)
|
||||
: this(ArrayHelper.safe_convert(favorite_algos, k => new bts.persist.algo.AlgoPersistedKey(k.persisted)), column_count) { }
|
||||
public LadderFavoriteAlgosSettings(AlgoKey[] favorite_algos, int column_count, AlgoKey[] stickied_algos)
|
||||
: this(ArrayHelper.safe_convert(favorite_algos, k => new bts.persist.algo.AlgoPersistedKey(k.persisted)),
|
||||
column_count,
|
||||
ArrayHelper.safe_convert(stickied_algos, k => new bts.persist.algo.AlgoPersistedKey(k.persisted))) { }
|
||||
|
||||
LadderFavoriteAlgosSettings(bts.persist.algo.AlgoPersistedKey[] favorite_algos, int column_count) {
|
||||
LadderFavoriteAlgosSettings(bts.persist.algo.AlgoPersistedKey[] favorite_algos, int column_count, bts.persist.algo.AlgoPersistedKey[] stickied_algos) {
|
||||
_favorite_algos = favorite_algos;
|
||||
this.column_count = column_count;
|
||||
_stickied_algos = stickied_algos;
|
||||
}
|
||||
|
||||
public IReadOnlyList<AlgoKey> favorite_algos => ArrayHelper.safe_convert(_favorite_algos, k => k.to_algo_key());
|
||||
public IReadOnlyList<AlgoKey> stickied_algos => ArrayHelper.safe_convert(_stickied_algos, k => k.to_algo_key());
|
||||
|
||||
public bool Equals(LadderFavoriteAlgosSettings other) =>
|
||||
column_count == other.column_count &&
|
||||
favorite_algos.SequenceEqual(other.favorite_algos);
|
||||
favorite_algos.SequenceEqual(other.favorite_algos) &&
|
||||
stickied_algos.SequenceEqual(other.stickied_algos);
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
EqualityComparer.equals_obj(this, obj);
|
||||
@@ -215,7 +222,8 @@ namespace mbts.spark {
|
||||
public override int GetHashCode() =>
|
||||
EqualityComparer.aggregate_hash(
|
||||
column_count,
|
||||
EqualityComparer.aggregate_hash_limited(favorite_algos));
|
||||
EqualityComparer.aggregate_hash_limited(favorite_algos),
|
||||
EqualityComparer.aggregate_hash_limited(stickied_algos));
|
||||
|
||||
public static bool operator ==(LadderFavoriteAlgosSettings a, LadderFavoriteAlgosSettings b) => a.Equals(b);
|
||||
public static bool operator !=(LadderFavoriteAlgosSettings a, LadderFavoriteAlgosSettings b) => !a.Equals(b);
|
||||
@@ -273,7 +281,7 @@ namespace mbts.spark {
|
||||
order_entry_panel_initial_width = _default_order_entry_panel_width;
|
||||
zoom_factor = _default_zoom_factor;
|
||||
use_defaults = true;
|
||||
favorite_algos = new LadderFavoriteAlgosSettings(null, 2);
|
||||
favorite_algos = new LadderFavoriteAlgosSettings(null, 2, null);
|
||||
show_warn_on_cross = _default_show_warn_on_cross;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ using ProtoBuf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
@@ -22,6 +23,7 @@ using LadderSettings = mbts.spark.LadderSettings;
|
||||
namespace bts.shell {
|
||||
class LadderWindowFactory : ShellWindowFactory<LadderSaveState> {
|
||||
const string _window_type = "ladder";
|
||||
const int _version_where_stickied_algos_introduced = 2;
|
||||
readonly LadderConfig _ladder_conf;
|
||||
readonly IBus _bus;
|
||||
readonly IWindowManager _wm;
|
||||
@@ -38,7 +40,7 @@ namespace bts.shell {
|
||||
OrdersModel orders_model,
|
||||
MBOService mbo)
|
||||
|
||||
: base(owner, "SparkLadder") {
|
||||
: base(owner, "SparkLadder", 2) {
|
||||
_bus = bus;
|
||||
_wm = wm;
|
||||
_settings_hub = settings_hub;
|
||||
@@ -60,6 +62,16 @@ namespace bts.shell {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override Task<IShellWindow> try_upgrade_state(Stream load_stream, int version) {
|
||||
var state = ProtoBuf.Serializer.DeserializeWithLengthPrefix<LadderSaveState>(load_stream, ProtoBuf.PrefixStyle.Fixed32);
|
||||
if (version < _version_where_stickied_algos_introduced) {
|
||||
// We want to assign any existing favorite algos to stickied algos upon setting upgrade
|
||||
var favorite_algos_array = state.settings.favorite_algos.favorite_algos.ToArray();
|
||||
state.settings.favorite_algos = new LadderFavoriteAlgosSettings(favorite_algos_array, state.settings.favorite_algos.column_count, favorite_algos_array);
|
||||
}
|
||||
return load(state);
|
||||
}
|
||||
|
||||
LadderSaveState _get_state(LadderVM vm, uint id) {
|
||||
LadderSettings s = vm.get_save_state();
|
||||
if (id != 0) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using bts.api;
|
||||
using bts.api.orderman;
|
||||
using bts.collections;
|
||||
using bts.persist.algo;
|
||||
using bts.shell.orderbook;
|
||||
using bts.utils;
|
||||
using mbts.collections;
|
||||
@@ -723,12 +724,15 @@ namespace mbts.spark {
|
||||
readonly IObservableCollection<AlgoDefinitionVM> _algo_definitions;
|
||||
readonly ObservableCollection<FavoriteAlgoItem> _raw_items = new ObservableCollection<FavoriteAlgoItem>();
|
||||
int _column_count = 2;
|
||||
HashSet<AlgoPersistedKey> _sticky_algo_keys;
|
||||
IDisposable _sticky_algos_hook;
|
||||
|
||||
public FavoriteAlgosVM(IObservableCollection<AlgoDefinitionVM> algo_definitions) {
|
||||
_algo_definitions = algo_definitions;
|
||||
items = new ObservableAggregateCollection<FavoriteAlgoItem>(_raw_items, new ObservableCollection<FavoriteAlgoItem> { FavoriteAlgoItem.AddButtonPlaceholderItem });
|
||||
add_item_cmd = new DelegateCommand(() => _raw_items.Add(_item_factory()));
|
||||
remove_item_cmd = new DelegateCommand<FavoriteAlgoItem>(fai => _raw_items.Remove(fai));
|
||||
_dispose = Disposable.Create(() => Disposable.dispose(ref _sticky_algos_hook));
|
||||
}
|
||||
|
||||
public ObservableCollection<FavoriteAlgoItem> items { get; }
|
||||
@@ -745,6 +749,17 @@ namespace mbts.spark {
|
||||
fai.selector.try_select(k);
|
||||
return fai;
|
||||
}));
|
||||
_sticky_algo_keys = new HashSet<AlgoPersistedKey>(value.stickied_algos.Where(k => k.is_persisted).Select(x => new AlgoPersistedKey(x.persisted)));
|
||||
Disposable.replace(ref _sticky_algos_hook,
|
||||
ObservableAutoWrapper.connect_item_hooks(_raw_items, x =>
|
||||
x.selector.subscribe_value().Subscribe(algo => {
|
||||
if (algo != null &&
|
||||
algo.key.is_persisted &&
|
||||
(x.is_sticky = _sticky_algo_keys.Remove(new AlgoPersistedKey(algo.key.persisted))) &&
|
||||
_sticky_algo_keys.Count == 0)
|
||||
//
|
||||
Disposable.dispose(ref _sticky_algos_hook);
|
||||
})));
|
||||
}
|
||||
|
||||
public LadderFavoriteAlgosSettings create() =>
|
||||
@@ -753,7 +768,13 @@ namespace mbts.spark {
|
||||
.Where(k => k.HasValue && k.Value.is_persisted)
|
||||
.Select(k => k.Value)
|
||||
.ToArray(),
|
||||
column_count);
|
||||
column_count,
|
||||
_raw_items
|
||||
.Where(fai => fai.is_sticky)
|
||||
.Select(fai => fai.algo_definition?.key ?? fai.selector.desired_key)
|
||||
.Where(k => k.HasValue && k.Value.is_persisted)
|
||||
.Select(k => k.Value)
|
||||
.ToArray());
|
||||
|
||||
FavoriteAlgoItem _item_factory() =>
|
||||
new FavoriteAlgoItem(_algo_definitions, new ListCollectionView<AlgoDefinitionVM>(_algo_definitions) {
|
||||
@@ -766,6 +787,7 @@ namespace mbts.spark {
|
||||
public static readonly FavoriteAlgoItem AddButtonPlaceholderItem = new _AddButtonPlaceholderItem();
|
||||
|
||||
internal readonly KeyedItemSelector<AlgoDefinitionVM, AlgoKey> selector;
|
||||
bool _is_sticky;
|
||||
|
||||
protected FavoriteAlgoItem() { }
|
||||
|
||||
@@ -776,6 +798,7 @@ namespace mbts.spark {
|
||||
|
||||
public ICollectionView<AlgoDefinitionVM> algo_definitions_view { get; }
|
||||
public AlgoDefinitionVM algo_definition { get => selector.value; set => selector.value = value; }
|
||||
public bool is_sticky { get => _is_sticky; set => Set(ref _is_sticky, value); }
|
||||
|
||||
class _AddButtonPlaceholderItem : FavoriteAlgoItem, ITemplateSelectorKey {
|
||||
public string key => LadderSettingsView.FavoriteAlgoAddButtonTemplateKey;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using bts.api;
|
||||
using bts.api.orderman;
|
||||
using bts.collections;
|
||||
using bts.shell;
|
||||
using bts.spark;
|
||||
using bts.utils;
|
||||
using mbts.co2;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
using mbts.utils;
|
||||
@@ -32,6 +34,7 @@ namespace mbts.spark {
|
||||
_show_tif, _show_order_type, _show_size_preset, _show_auto_clear, _show_clear, _show_cancel_buys,
|
||||
_show_cancel_sells, _show_cancel_all, _show_zoom;
|
||||
readonly PropertyAutoWrapper<LadderSettings, Brush> _bid_background, _bid_foreground, _ask_background, _ask_foreground;
|
||||
readonly HashSet<AlgoKey> _sticky_algos = new HashSet<AlgoKey>();
|
||||
double _position, _day_position;
|
||||
bool _show_account_position, _show_day_position;
|
||||
ulong _misc_time = 0;
|
||||
@@ -133,7 +136,7 @@ namespace mbts.spark {
|
||||
//_window_height = backing(nameof(window_height), settings_manager.subscribe_current().OnDispatcher().Select(s => s.zoom_factor), (scale) => scale * 600);
|
||||
//_window_width = backing(nameof(window_width), settings_manager.subscribe_current().OnDispatcher().Select(s => s.zoom_factor), (scale) => scale * 420);
|
||||
position_click_command = new DelegateCommand(() => size_calculator.value = DoubleHelper.safe_convert_to_uint(Math.Abs(_show_day_position ? day_position : position)));
|
||||
send_order_command = new DelegateCommand<(double price, Side? side, MouseButton button)>(send_order);
|
||||
send_order_command = new AsyncCommand<(double price, Side? side, MouseButton button)>(send_order_async);
|
||||
cancel_command = new AsyncCommand<LadderModel.CancelType>(_model.cancel_orders, true);
|
||||
show_book_command = new DelegateCommand(_show_book);
|
||||
show_ticket_command = new DelegateCommand(_show_ticket);
|
||||
@@ -223,7 +226,10 @@ namespace mbts.spark {
|
||||
.SelectManyInSeries(a => _model.order_gateway.on_security_positions(security.Id)
|
||||
.Select(table => table.state.Values.FirstOrDefault(pos => pos.Item2.Account == a, tup => tup.Item2, (bts.api.position.PositionUnitImmutable?)null)));
|
||||
return Disposable.Create(
|
||||
settings.OnDispatcher().Subscribe(s => order_properties_vm.on_favorite_algos(s.favorite_algos)),
|
||||
settings.OnDispatcher().Subscribe(s => {
|
||||
_sticky_algos.SetItems(s.favorite_algos.stickied_algos);
|
||||
order_properties_vm.on_favorite_algos(s.favorite_algos);
|
||||
}),
|
||||
order_properties_vm,
|
||||
position_src.OnDispatcher().Subscribe(pos => {
|
||||
double total, day;
|
||||
@@ -400,20 +406,19 @@ namespace mbts.spark {
|
||||
settings_invalidated?.Invoke();
|
||||
}
|
||||
|
||||
public void send_order((double price, Side? side, MouseButton button) args) {
|
||||
if (order_properties_vm == null || args.button == MouseButton.Middle)
|
||||
return;
|
||||
var size_from_alternate = args.button == MouseButton.Right;
|
||||
if (DoubleHelper.IsNaNOrInfinity(args.price) || !args.side.HasValue || HasErrors || order_properties_vm.HasErrors || (size_from_alternate && current_settings.alternate_order_size == 0)) {
|
||||
return;
|
||||
}
|
||||
if (!size_from_alternate && (!size_calculator.value.HasValue || size_calculator.value.Value == 0)) {
|
||||
size_calculator.flash_error();
|
||||
}
|
||||
else {
|
||||
uint size = size_from_alternate ? current_settings.alternate_order_size : (uint)Math.Abs(size_calculator.value ?? 0);
|
||||
send_order_async(args.side.Value, size, args.price).ignore();
|
||||
public Task send_order_async((double price, Side? side, MouseButton button) args) {
|
||||
if (order_properties_vm != null && args.button != MouseButton.Middle) {
|
||||
var size_from_alternate = args.button == MouseButton.Right;
|
||||
if (!DoubleHelper.IsNaNOrInfinity(args.price) && args.side.HasValue && !HasErrors && !order_properties_vm.HasErrors && (!size_from_alternate || current_settings.alternate_order_size > 0)) {
|
||||
if (!size_from_alternate && (!size_calculator.value.HasValue || size_calculator.value.Value == 0)) {
|
||||
size_calculator.flash_error();
|
||||
} else {
|
||||
uint size = size_from_alternate ? current_settings.alternate_order_size : (uint)Math.Abs(size_calculator.value ?? 0);
|
||||
return send_order_async(args.side.Value, size, args.price);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task send_order_async(Side side, uint size, double price) {
|
||||
@@ -433,6 +438,13 @@ namespace mbts.spark {
|
||||
await _model.order_gateway.send_order(order, price, size);
|
||||
if (auto_clear)
|
||||
size_calculator.value = 0;
|
||||
var fav_algo = order_properties_vm.selected_favorite_algo_definition;
|
||||
if (fav_algo != null && !_sticky_algos.Contains(fav_algo.key) && !order_properties_vm.try_pop_selected_algo_definition()) {
|
||||
var key = new AlgoKey(OrderDataHelper.get_default_algo(OrderDataHelper.get_algo_format(security.ContractCase)));
|
||||
if (order_properties_vm.try_get_algo_definition(key, out var r)) {
|
||||
order_properties_vm.selected_algo_definition = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _update_header() {
|
||||
|
||||
@@ -805,6 +805,7 @@
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="c0"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="c1"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Command="{Binding DataContext.remove_item_cmd, RelativeSource={RelativeSource AncestorType=ItemsControl}}" CommandParameter="{Binding}" Style="{StaticResource RoundCloseButton}"/>
|
||||
<ComboBox Grid.Column="1" ItemsSource="{Binding algo_definitions_view}" SelectedItem="{Binding algo_definition}">
|
||||
@@ -814,6 +815,7 @@
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<CheckBox Grid.Column="2" VerticalAlignment="Center" VerticalContentAlignment="Center" IsChecked="{Binding is_sticky}"> Stay Enabled?</CheckBox>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</u:KeyedTemplateSelector.Default>
|
||||
@@ -823,6 +825,7 @@
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="c0"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="c1"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="1" HorizontalAlignment="Stretch" Command="{Binding DataContext.add_item_cmd, RelativeSource={RelativeSource AncestorType=ItemsControl}}">Add</Button>
|
||||
</Grid>
|
||||
|
||||
@@ -631,25 +631,54 @@ namespace mbts.spark.utilities {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
static CustomOrderDefinition.CustomOneofCase[] algo_config(
|
||||
Func<bts.config.AlgoPermissions, List<string>> selector)
|
||||
{
|
||||
var conf = mbts.config.Configuration.get<bts.config.AlgoPermissions>();
|
||||
return selector(conf).Select(x =>
|
||||
{
|
||||
return (CustomOrderDefinition.CustomOneofCase)System.Enum.Parse(typeof(CustomOrderDefinition.CustomOneofCase), x, true);
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
public static readonly CustomOrderDefinition.CustomOneofCase[]
|
||||
|
||||
// exchange_order_types are the types which can be submitted on an exchange security
|
||||
exchange_order_types = algo_config(x => x.exchange_order_types),
|
||||
spreader_order_types = algo_config(x => x.spreader_order_types),
|
||||
attachable_order_types = algo_config(x => x.attachable_order_types),
|
||||
outright_order_types = algo_config(x => x.outright_order_types);
|
||||
|
||||
exchange_order_types = new[] {
|
||||
CustomOrderDefinition.CustomOneofCase.Market,
|
||||
CustomOrderDefinition.CustomOneofCase.Limit,
|
||||
CustomOrderDefinition.CustomOneofCase.Stop,
|
||||
CustomOrderDefinition.CustomOneofCase.StopLimit,
|
||||
CustomOrderDefinition.CustomOneofCase.GlbxIceberg,
|
||||
CustomOrderDefinition.CustomOneofCase.Iceberg,
|
||||
CustomOrderDefinition.CustomOneofCase.Lean,
|
||||
CustomOrderDefinition.CustomOneofCase.Join,
|
||||
CustomOrderDefinition.CustomOneofCase.Cover,
|
||||
CustomOrderDefinition.CustomOneofCase.Top,
|
||||
CustomOrderDefinition.CustomOneofCase.Offset,
|
||||
CustomOrderDefinition.CustomOneofCase.Splitter,
|
||||
CustomOrderDefinition.CustomOneofCase.Scratch,
|
||||
CustomOrderDefinition.CustomOneofCase.Prorata,
|
||||
},
|
||||
spreader_order_types = new[] {
|
||||
CustomOrderDefinition.CustomOneofCase.Spreader,
|
||||
CustomOrderDefinition.CustomOneofCase.Iceberg,
|
||||
CustomOrderDefinition.CustomOneofCase.Lean,
|
||||
CustomOrderDefinition.CustomOneofCase.Join,
|
||||
CustomOrderDefinition.CustomOneofCase.Cover,
|
||||
CustomOrderDefinition.CustomOneofCase.Top,
|
||||
CustomOrderDefinition.CustomOneofCase.Splitter,
|
||||
CustomOrderDefinition.CustomOneofCase.Scratch,
|
||||
CustomOrderDefinition.CustomOneofCase.Prorata,
|
||||
},
|
||||
attachable_order_types = new[] {
|
||||
CustomOrderDefinition.CustomOneofCase.Iceberg,
|
||||
CustomOrderDefinition.CustomOneofCase.Lean,
|
||||
CustomOrderDefinition.CustomOneofCase.Join,
|
||||
CustomOrderDefinition.CustomOneofCase.Cover,
|
||||
CustomOrderDefinition.CustomOneofCase.Top,
|
||||
CustomOrderDefinition.CustomOneofCase.Offset,
|
||||
CustomOrderDefinition.CustomOneofCase.Scratch,
|
||||
CustomOrderDefinition.CustomOneofCase.Prorata,
|
||||
},
|
||||
outright_order_types = new[] {
|
||||
CustomOrderDefinition.CustomOneofCase.Market,
|
||||
CustomOrderDefinition.CustomOneofCase.Limit,
|
||||
CustomOrderDefinition.CustomOneofCase.Stop,
|
||||
CustomOrderDefinition.CustomOneofCase.StopLimit,
|
||||
CustomOrderDefinition.CustomOneofCase.GlbxIceberg,
|
||||
};
|
||||
public static readonly CustomOrderDefinition.CustomOneofCase[] all_order_types = exchange_order_types.Union(spreader_order_types).ToArray();
|
||||
|
||||
public static void copy_values(CustomOrderDefinitionImmutable source, ref CustomOrderDefinition target) =>
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace mbts.spark {
|
||||
readonly ListCollectionView<AlgoDefinitionVM> _algo_definitions_view, _favorite_algo_definitions_view;
|
||||
readonly TableUpdateBuffer<AlgoData, AlgoKey> _definitions_buffer = new TableUpdateBuffer<AlgoData, AlgoKey>(d => d.key);
|
||||
readonly ObservableAggregateCollection<AlgoParamRowVM> _algo_param_rows = new ObservableAggregateCollection<AlgoParamRowVM>();
|
||||
readonly AlgoDefinitionVM the_anchor_algo_def_vm;
|
||||
IReadOnlyDictionary<AlgoKey, AlgoDefinitionMetadata> _algo_metadata = DictionaryHelper.empty<AlgoKey, AlgoDefinitionMetadata>();
|
||||
IReadOnlyDictionary<AlgoKey, int> _favorite_algos_index = DictionaryHelper.empty<AlgoKey, int>();
|
||||
IDisposable _algo_param_rows_hook;
|
||||
@@ -68,6 +69,7 @@ namespace mbts.spark {
|
||||
|
||||
public OrderPropertiesEditorVM(OrdersModel model, IObservable<SecurityMD> security_md_source, IObservable<InlineOrderProperties> order_properties) {
|
||||
_model = model;
|
||||
the_anchor_algo_def_vm = AlgoDefinitionVM.create(_model, OrderDataHelper.Defaults.AlgoData(CustomOrderDefinition.CustomOneofCase.Limit));
|
||||
var security_source = security_md_source.Select(smd => smd.security);
|
||||
_security = backing(nameof(security), security_source, SecurityDataHelper.Defaults.SecurityImmutable);
|
||||
security_source = _security.observe_current(true);
|
||||
@@ -237,11 +239,15 @@ namespace mbts.spark {
|
||||
|
||||
void _selected_algo_definition_Changed(AlgoDefinitionVM old_value, AlgoDefinitionVM new_value, SelectionReason reason) {
|
||||
Disposable.dispose(ref _algo_param_rows_hook);
|
||||
if (old_value != null)
|
||||
// Taha feels that we should always revert to a Limit order either when the user explicity unchecks a sticky button
|
||||
// or when a non-sticky button is pressed. Rather than completely remove the stack at this time (b/c it may be come
|
||||
// back in the future), let's just always push a specfic def_vm.key onto it [Limit] ;)
|
||||
//_selected_algo_stack.Push(old_value.key);
|
||||
_selected_algo_stack.Push(the_anchor_algo_def_vm.key);
|
||||
if (new_value != null) {
|
||||
if (use_algo_param_grid)
|
||||
_algo_param_rows_hook = _connect_algo_param_rows(new_value, _algo_param_rows);
|
||||
if (reason != SelectionReason.Explicit)
|
||||
_selected_algo_stack.Push(new_value.key);
|
||||
}
|
||||
if (open_algo_popup_on_select) {
|
||||
if (reason == SelectionReason.UserSelectedNewValue && new_value?.algo_root is IAlgoVM ar && ar.can_expand)
|
||||
@@ -277,6 +283,18 @@ namespace mbts.spark {
|
||||
get => _selected_algo_definition.selected_item;
|
||||
set => _selected_algo_definition.selected_item = value;
|
||||
}
|
||||
|
||||
public bool try_get_algo_definition(AlgoKey a, out AlgoDefinitionVM result) =>
|
||||
_algo_definitions.TryGetValue(a, out result);
|
||||
|
||||
public bool try_pop_selected_algo_definition() {
|
||||
if (_selected_algo_stack.TryPop(out AlgoKey k) && _algo_definitions.TryGetValue(k, out AlgoDefinitionVM vm)) {
|
||||
_selected_algo_definition.select_explicit(vm);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public AlgoDefinitionVM selected_favorite_algo_definition {
|
||||
get => selected_algo_definition?.is_favorite ?? false ? selected_algo_definition : null;
|
||||
set {
|
||||
@@ -353,6 +371,7 @@ namespace mbts.spark {
|
||||
d.favorite_index = _get_favorite_algo_index(d.key);
|
||||
}
|
||||
favorite_algos_column_count = value.column_count;
|
||||
RaisePropertyChanged(nameof(selected_favorite_algo_definition));
|
||||
}
|
||||
|
||||
static IDisposable _connect_algo_param_rows(AlgoDefinitionVM def, ObservableAggregateCollection<AlgoParamRowVM> rows) =>
|
||||
@@ -371,4 +390,4 @@ namespace mbts.spark {
|
||||
algo_definitions_view.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,13 +34,14 @@ namespace bts.shell {
|
||||
Disposable.dispose(ref _dispose);
|
||||
}
|
||||
public abstract Task<IShellWindow> load(T state);
|
||||
protected virtual Task<IShellWindow> try_upgrade_state(Stream load_stream, int version) => null;
|
||||
|
||||
public Task<IShellWindow> load_window(Stream load_stream, int version) {
|
||||
if (version == this.version) {
|
||||
var t = ProtoBuf.Serializer.DeserializeWithLengthPrefix<T>(load_stream, ProtoBuf.PrefixStyle.Fixed32);
|
||||
return load(t);
|
||||
}
|
||||
return null;
|
||||
return try_upgrade_state(load_stream, version);
|
||||
}
|
||||
public void save(T data, Stream output) {
|
||||
var header = new ShellSerializationHeader() {
|
||||
|
||||
@@ -96,6 +96,7 @@ namespace mbts.ui.controls {
|
||||
Aggressor = "Aggressor",
|
||||
Volume = "Volume",
|
||||
Last = "Last",
|
||||
S = "S",
|
||||
Pos = "Pos",
|
||||
Working = "Working",
|
||||
Bid = "Bid",
|
||||
@@ -105,6 +106,7 @@ namespace mbts.ui.controls {
|
||||
SessionLow = "Low",
|
||||
SessionHigh = "High",
|
||||
FillKind = "Fill Kind",
|
||||
FillStatus = "Fill Status",
|
||||
Name = "Name",
|
||||
Description = "Description",
|
||||
N_Legs = "# Legs",
|
||||
|
||||
@@ -236,12 +236,12 @@ namespace mbts.ui {
|
||||
throw new NotImplementedException("This ICommand does not implement IRaiseCanExecuteChanged");
|
||||
}
|
||||
|
||||
public static async Task ExecuteAsync(this ICommand command, object parameter) {
|
||||
public static Task ExecuteAsync(this ICommand command, object parameter) {
|
||||
ExceptionAssert.Argument.NotNull(command, nameof(command));
|
||||
if (command is IAsyncCommand acmd)
|
||||
await acmd.Execute(parameter);
|
||||
return acmd.Execute(parameter);
|
||||
else
|
||||
await Task.Run(() => command.Execute(parameter));
|
||||
return Task.Run(() => command.Execute(parameter));
|
||||
}
|
||||
|
||||
public static void TryExecuteIfCan(this ICommand command, object parameter) {
|
||||
|
||||
@@ -136,8 +136,8 @@ namespace mbts.spark {
|
||||
var skip_local = profiles.WrapSkip(1);
|
||||
var skip_local_wrapper = skip_local.WrapSelector(
|
||||
p => new SettingsProfile<T>(p.id, p.name, p.value.create(), p.security_criteria),
|
||||
ns => new ProfileVM(ns.id, vm_factory(ns.value), ns.name, ns.security_criteria));
|
||||
profiles.Add(_local_profile = new ProfileVM(0, vm_factory(init), "Custom", template_key: ShellSettingsDialog.LocalProfileItemTemplateKey));
|
||||
ns => new ProfileVM(ns.id, vm_factory(ns.value), ns.name, ns.security_criteria, target_value: ns.value));
|
||||
profiles.Add(_local_profile = new ProfileVM(0, vm_factory(init), "Custom", template_key: ShellSettingsDialog.LocalProfileItemTemplateKey, target_value: init));
|
||||
_selected_profile = backing(nameof(selected_profile), _local_profile);
|
||||
// dialog skirt items
|
||||
_apply_item = new DialogSkirtItem("Apply", new DelegateCommand(apply));
|
||||
@@ -325,26 +325,37 @@ namespace mbts.spark {
|
||||
//
|
||||
SecurityCriteria _security_criteria;
|
||||
SettingsProfile<T> _committed, _last_result;
|
||||
T _target_value;
|
||||
string _name, _template_key;
|
||||
bool _is_selected;
|
||||
IDisposable _dispose;
|
||||
|
||||
public ProfileVM(uint id, TVM value, string name, SecurityCriteria security_criteria = null, string template_key = null) {
|
||||
public ProfileVM(uint id, TVM value, string name, SecurityCriteria security_criteria = null, string template_key = null, T target_value = null) {
|
||||
this.id = id;
|
||||
this.value = value;
|
||||
_name = name;
|
||||
_security_criteria = security_criteria;
|
||||
_template_key = template_key;
|
||||
_target_value = target_value;
|
||||
_committed = _last_result = create();
|
||||
_is_dirty = backing(nameof(is_dirty), () => !_last_result.Equals(_committed));
|
||||
_refresh_is_dirty = new DeferrableActionWrapper(_is_dirty.refresh);
|
||||
var sub = value.Subscribe(v => {
|
||||
_last_result = _last_result.with(value: v);
|
||||
_refresh_is_dirty.execute();
|
||||
_on_value_changed();
|
||||
});
|
||||
_dispose = value is IDisposable d ? Disposable.Create(sub, d) : sub;
|
||||
}
|
||||
|
||||
void _on_value_changed() {
|
||||
if (_target_value != null && is_dirty && _last_result.value.Equals(_target_value)) {
|
||||
_target_value = null;
|
||||
_committed = _last_result;
|
||||
_refresh_is_dirty.execute();
|
||||
}
|
||||
}
|
||||
|
||||
public uint id { get; }
|
||||
public TVM value { get; }
|
||||
public string name {
|
||||
@@ -380,21 +391,26 @@ namespace mbts.spark {
|
||||
/// assign directly to <see cref="_last_result"/>, to capture props that aren't visible in the dialog (i.e., props that are manipulated in the main window)
|
||||
_last_result = data;
|
||||
}
|
||||
_on_value_changed();
|
||||
}
|
||||
|
||||
public void load_value_from(T value) {
|
||||
using (_refresh_is_dirty.defer_execution())
|
||||
this.value.load_from(value);
|
||||
_on_value_changed();
|
||||
}
|
||||
|
||||
public void commit(SettingsProfile<T> data) {
|
||||
using (_refresh_is_dirty.defer_execution())
|
||||
_load_from(_committed = data);
|
||||
_on_value_changed();
|
||||
}
|
||||
|
||||
public void commit_current() {
|
||||
_committed = _last_result;
|
||||
_target_value = _committed.value;
|
||||
_refresh_is_dirty.execute();
|
||||
_on_value_changed();
|
||||
}
|
||||
|
||||
public void revert() {
|
||||
@@ -402,6 +418,7 @@ namespace mbts.spark {
|
||||
_load_from(_committed);
|
||||
_last_result = _committed;
|
||||
}
|
||||
_on_value_changed();
|
||||
}
|
||||
|
||||
public IObservable<bool> subscribe_is_dirty() => _is_dirty.observe_current(true);
|
||||
@@ -414,6 +431,7 @@ namespace mbts.spark {
|
||||
public override string ToString() => _name;
|
||||
|
||||
void _load_from(SettingsProfile<T> data) {
|
||||
_target_value = data.value;
|
||||
name = data.name;
|
||||
security_criteria = data.security_criteria;
|
||||
value.load_from(data.value);
|
||||
|
||||
@@ -133,6 +133,12 @@ namespace mbts.co2 {
|
||||
total_volume = _cold->total_volume;
|
||||
return (_cold->last_trade.load_if_new(ref time, out ps));
|
||||
}
|
||||
public bool get_last_trade(ref ulong time, out NativePriceSize ps, out DateTime timestamp, out ulong total_volume, out bool from_spread) {
|
||||
timestamp = _cold->last_trade_time;
|
||||
total_volume = _cold->total_volume;
|
||||
from_spread = (_cold->from_spread != 0);
|
||||
return (_cold->last_trade.load_if_new(ref time, out ps));
|
||||
}
|
||||
public ulong misc_timestamp { get { return _cold->misc_timestamp; } }
|
||||
|
||||
public ulong total_volume { get { return _cold->total_volume; } }
|
||||
@@ -259,7 +265,7 @@ namespace mbts.co2 {
|
||||
// Last trade
|
||||
public AtomicPriceSize last_trade;
|
||||
public ulong total_volume;
|
||||
public utils.LLDateTime last_trade_time;
|
||||
public utils.LLDateTime last_trade_time;
|
||||
|
||||
//// Settlement
|
||||
public UInt64 misc_timestamp;
|
||||
@@ -280,6 +286,7 @@ namespace mbts.co2 {
|
||||
public double session_low_offer;
|
||||
public double fixing_price;
|
||||
|
||||
public int from_spread;
|
||||
public int deleted;
|
||||
// FixedSecurity will not be directly addressable. Instead the security is available through the callback
|
||||
public Int64 security_size;
|
||||
|
||||
@@ -142,7 +142,8 @@ namespace mbts.co2.tests
|
||||
Assert.IsTrue(entry.session_low_offer == 5.5);
|
||||
Assert.IsTrue(entry.fixing_price == 6.6);
|
||||
|
||||
Assert.IsTrue(entry.deleted == 1);
|
||||
Assert.IsTrue(entry.from_spread == 0);
|
||||
Assert.IsTrue(entry.deleted == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -85,6 +85,8 @@ namespace bts.tests.utils {
|
||||
if(timeout == null) {
|
||||
timeout = TimeSpan.FromMinutes(2);
|
||||
}
|
||||
Console.WriteLine("Please Wait... this is going to take some time...");
|
||||
await Task.Delay(180000);
|
||||
|
||||
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
-->
|
||||
<connectivityConfiguration>
|
||||
<!-- TCP Connection Information -->
|
||||
|
||||
<tcp>
|
||||
<server name="default">
|
||||
<ip>63.247.113.163</ip>
|
||||
@@ -19,7 +18,7 @@
|
||||
<userName>bluetrd-ps</userName>
|
||||
<password>Starts123</password>
|
||||
<getStripInfoMessages>N</getStripInfoMessages>
|
||||
<strategyPreference>Legacy</strategyPreference>
|
||||
<strategyPreference>New</strategyPreference>
|
||||
<localNetworkInterface></localNetworkInterface>
|
||||
</server>
|
||||
<server name="endex">
|
||||
@@ -28,7 +27,7 @@
|
||||
<userName>Value from ICE Support</userName>
|
||||
<password>Value from ICE Support</password>
|
||||
<getStripInfoMessages>N</getStripInfoMessages>
|
||||
<strategyPreference>Legacy</strategyPreference>
|
||||
<strategyPreference>New</strategyPreference>
|
||||
<localNetworkInterface></localNetworkInterface>
|
||||
</server>
|
||||
<server name="liffe-eu">
|
||||
@@ -37,7 +36,7 @@
|
||||
<userName>bluetrdl-ps</userName>
|
||||
<password>Starts123</password>
|
||||
<getStripInfoMessages>N</getStripInfoMessages>
|
||||
<strategyPreference>Legacy</strategyPreference>
|
||||
<strategyPreference>New</strategyPreference>
|
||||
<localNetworkInterface></localNetworkInterface>
|
||||
</server>
|
||||
<settings>
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
<server name="default">
|
||||
<ip>63.247.113.214</ip>
|
||||
<port>3000</port>
|
||||
<userName>Value from ICE Support</userName>
|
||||
<password>Value from ICE Support</password>
|
||||
<userName>bt_ps</userName>
|
||||
<password>Starts123</password>
|
||||
<getStripInfoMessages>N</getStripInfoMessages>
|
||||
<strategyPreference>Legacy</strategyPreference>
|
||||
<strategyPreference>New</strategyPreference>
|
||||
<localNetworkInterface></localNetworkInterface>
|
||||
</server>
|
||||
<settings>
|
||||
|
||||
@@ -1 +1 @@
|
||||
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/service_helpers/AlgoServiceUtils.cpp;api/services/AdminService.proto;api/services/AlgoDefinitionService.proto;api/services/AlgoService.proto;api/services/ApiUnitTestService.proto;api/services/AuthService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/HistoricalDataService.proto;api/services/MBOService.proto;api/services/MarginService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/UI.conf;config/defaults/cme_reference_data.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/keycode.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/span.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/jetfix.proto;config/protos/keycode.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/span.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPeriodicDumper.cpp;md/Diag/ShmDumper.cpp;md/MBOProcessor.cpp;md/MBOServiceServer.cpp;md/MDClient.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityCache.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SecurityOracle.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/ice/ICEUtils.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/mbo_tests.cpp;md/test/md2_tests.cpp;md/test/md_test_utils.cpp;md/test/synthetic_book_merge_tests.cpp;os/os.cpp;os/tests/os_tests.cpp;quickbus/core/LocalNode.cpp;quickbus/core/Quickbus.cpp;quickbus/core/SubscriptionID.cpp;quickbus/core/TableID.cpp;quickbus/message_model/Update.cpp;quickbus/message_model/merge_updates.cpp;quickbus/network/QBConnection.cpp;quickbus/network/QBConnectionManager.cpp;quickbus/network/endpoint_description.cpp;quickbus/network/quickbus_msgs.proto;quickbus/pubsub/TablePublisher.cpp;quickbus/pubsub/TableSubscriber.cpp;quickbus/pubsub/tests/qb_pubsub_tests.cpp;quickbus/routing/INode.cpp;quickbus/routing/NodeID.cpp;quickbus/routing/Router.cpp;quickbus/rpc/RPCClient.cpp;quickbus/rpc/RPCServer.cpp;quickbus/rpc/RPCSessionID.cpp;quickbus/rpc/rpc_utils.cpp;quickbus/rpc/tests/qb_rpc_tests.cpp;quickbus/tests/quickbus_tests.cpp;sparkproto/SparkProtos.proto;testing/catch_test_runner.cpp;utils/AuthSessionManager.cpp;utils/AuthToken.cpp;utils/Dispatcher.cpp;utils/GrowableSPSCQueue.cpp;utils/HTTPStream.cpp;utils/PBUtils.cpp;utils/Puid.cpp;utils/SecureLogon.cpp;utils/SharedMemory.cpp;utils/Sqlite_utils.cpp;utils/Uuid.cpp;utils/crypto/CipherType.cpp;utils/crypto/CryptoInit.cpp;utils/crypto/Digest.cpp;utils/crypto/KeyCodeHelper.cpp;utils/cryLine truncated
|
||||
set(sources api/apicore.proto;api/apigateway.proto;api/apioptions.proto;api/core/ApiClientInterop.cpp;api/core/ApiServerInterop.cpp;api/public/ApiServer.cpp;api/public/ClientChannel.cpp;api/public/QuickbusClientChannel.cpp;api/public/ServerChannel.cpp;api/public/ServiceContext.cpp;api/service_helpers/AdminServiceUtils.cpp;api/service_helpers/AlgoServiceUtils.cpp;api/services/AdminService.proto;api/services/AlgoDefinitionService.proto;api/services/AlgoService.proto;api/services/ApiUnitTestService.proto;api/services/AuthService.proto;api/services/ErrorReportService.proto;api/services/HelloService.proto;api/services/MBOService.proto;api/services/MarginService.proto;api/services/MarketDataAuxiliaryService.proto;api/services/MarketDataRelay.proto;api/services/OrderService.proto;api/services/OutOfProcessURLListener.proto;api/services/PersistenceService.proto;api/services/PositionService.proto;api/services/ShellDiagnosticService.proto;api/services/ShellLatencyService.proto;api/services/SyntheticSecurityService.proto;api/test/ApiTests.cpp;api/test/HelloServiceServer.cpp;config/ConfigCheck.cpp;config/ConfigDownloader.cpp;config/ConfigErrorCollector.cpp;config/ConfigLog.cpp;config/ConfigPropertyEvaluator.cpp;config/ConfigValueQueue.cpp;config/ConfigurationException.cpp;config/ConfigurationState.cpp;config/PreprocessInputStream.cpp;config/config.cpp;config/defaults/MarketData.conf;config/defaults/Ports.conf;config/defaults/Symbols.conf;config/defaults/cme_reference_data.conf;config/defaults/edge.conf;config/defaults/jetfix.conf;config/defaults/keycode.conf;config/defaults/logging.conf;config/defaults/orderman_cfg.conf;config/defaults/orders_fills_cleanup.conf;config/defaults/span.conf;config/defaults/spreader.conf;config/defaults/testkeys.conf;config/defaults/threads.conf;config/defaults/toggles.conf;config/extensions/extensions.proto;config/invalid/invalid.proto;config/protos/ExchangeSimCfg.proto;config/protos/MarketData.proto;config/protos/Ports.proto;config/protos/Symbols.proto;config/protos/UI.proto;config/protos/cme_reference_data.proto;config/protos/jetfix.proto;config/protos/keycode.proto;config/protos/logging.proto;config/protos/mercury_cfg.proto;config/protos/orderman_cfg.proto;config/protos/orders_fills_cleanup.proto;config/protos/perflog_cfg.proto;config/protos/quickbus_cfg.proto;config/protos/span.proto;config/protos/spreader.proto;config/protos/system.proto;config/protos/testkeys.proto;config/protos/threads.proto;config/protos/toggles.proto;config/tests/HTTPServer.cpp;config/tests/config_ref_tests.cpp;config/tests/config_tests.cpp;config/text_format/text_format.cpp;domain_model/Security.cpp;domain_model/Security.proto;domain_model/SecurityTests.cpp;domain_model/tests/domain_tests.cpp;expression/BooleanGrammar.cpp;expression/ExpressionEvaluator.cpp;expression/ParserExceptions.cpp;expression/Value.cpp;expression/tests/expression_parser_tests.cpp;logging/LoggerHub.cpp;logging/Sink.cpp;logging/logging.cpp;logging/tests/logging_tests.cpp;md/Diag/MDPeriodicDumper.cpp;md/Diag/ShmDumper.cpp;md/MBOProcessor.cpp;md/MBOServiceServer.cpp;md/MDClient.cpp;md/MDConsumer.cpp;md/MDConsumerHandle.cpp;md/MDConsumerInterop.cpp;md/MDProducer.cpp;md/MDProducerHandle.cpp;md/MemorySegmentUtils.cpp;md/PlatformLoader.cpp;md/PriceSize.cpp;md/SecurityCache.cpp;md/SecurityDB.cpp;md/SecurityIDRecorder.cpp;md/SecurityOracle.cpp;md/SettlementRecorder.cpp;md/Shm/FixedSecurity.cpp;md/SyntheticSecurityService.cpp;md/cme/MDP3Utils.cpp;md/common.cpp;md/ice/ICEUtils.cpp;md/protos/co2.proto;md/relay/QueryServer.cpp;md/relay/RelayClient.cpp;md/relay/RelayRecorder.cpp;md/test/Co2ManagedTestHelper.cpp;md/test/Co2TestInstrument.cpp;md/test/mbo_tests.cpp;md/test/md2_tests.cpp;md/test/md_test_utils.cpp;md/test/synthetic_book_merge_tests.cpp;os/os.cpp;os/tests/os_tests.cpp;quickbus/core/LocalNode.cpp;quickbus/core/Quickbus.cpp;quickbus/core/SubscriptionID.cpp;quickbus/core/TableID.cpp;quickbus/message_model/Update.cpp;quickbus/message_model/merge_updates.cpp;quickbus/network/QBConnection.cpp;quickbus/network/QBConnectionManager.cpp;quickbus/network/endpoint_description.cpp;quickbus/network/quickbus_msgs.proto;quickbus/pubsub/TablePublisher.cpp;quickbus/pubsub/TableSubscriber.cpp;quickbus/pubsub/tests/qb_pubsub_tests.cpp;quickbus/routing/INode.cpp;quickbus/routing/NodeID.cpp;quickbus/routing/Router.cpp;quickbus/rpc/RPCClient.cpp;quickbus/rpc/RPCServer.cpp;quickbus/rpc/RPCSessionID.cpp;quickbus/rpc/rpc_utils.cpp;quickbus/rpc/tests/qb_rpc_tests.cpp;quickbus/tests/quickbus_tests.cpp;sparkproto/SparkProtos.proto;testing/catch_test_runner.cpp;utils/AuthSessionManager.cpp;utils/AuthToken.cpp;utils/Dispatcher.cpp;utils/GrowableSPSCQueue.cpp;utils/HTTPStream.cpp;utils/PBUtils.cpp;utils/Puid.cpp;utils/SecureLogon.cpp;utils/SharedMemory.cpp;utils/Sqlite_utils.cpp;utils/Uuid.cpp;utils/crypto/CipherType.cpp;utils/crypto/CryptoInit.cpp;utils/crypto/Digest.cpp;utils/crypto/KeyCodeHelper.cpp;utils/crypto/PasswordCallback.cpp;utils/crypto/PrivateKey.cpp;utils/cryptoLine truncated
|
||||
@@ -141,3 +141,4 @@ if (WIN32)
|
||||
include(${CMAKE_SOURCE_DIR}/tools/vs_filters.cmake)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -42,12 +42,15 @@ bool AdminServiceUtils::has_exchange(const ExchangeConnection& conn,
|
||||
break;
|
||||
case api::Venue::VENUE_UNSET:
|
||||
case api::Venue::VENUE_SIM:
|
||||
case api::Venue::VENUE_SIMICE:
|
||||
rv = conn.has_sim_connection();
|
||||
break;
|
||||
case api::Venue::VENUE_ICE:
|
||||
rv = conn.has_ice_connection();
|
||||
break;
|
||||
case api::Venue::VENUE_BTS:
|
||||
case api::Venue::VENUE_CBOE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::VENUE_ICE:
|
||||
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
rv = false;
|
||||
@@ -84,6 +87,23 @@ AdminServiceUtils::resolve_cme_connection(const bts::api::admin::AdminData& data
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bts::api::admin::ExchangeConnection*
|
||||
AdminServiceUtils::resolve_ice_connection(const bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSAccount& account,
|
||||
const bts::api::Security&)
|
||||
{
|
||||
if(account.has_connections())
|
||||
{
|
||||
for (const std::string& conn_name : account.connections().exchange_connection_names())
|
||||
{
|
||||
const bts::api::admin::ExchangeConnection* conn = find_connection(data, conn_name);
|
||||
if (conn!=nullptr && conn->has_ice_connection())
|
||||
return conn;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bts::api::admin::ExchangeConnection*
|
||||
AdminServiceUtils::resolve_sim_connection(const bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSAccount& account,
|
||||
@@ -112,14 +132,22 @@ AdminServiceUtils::resolve_connection(const bts::api::admin::AdminData& data,
|
||||
rv = resolve_sim_connection(data, account, sec);
|
||||
break;
|
||||
}
|
||||
case api::Venue::VENUE_ICE:
|
||||
{
|
||||
rv = resolve_ice_connection(data, account, sec);
|
||||
auto deployment_type = boost::to_lower_copy(config::get<config::DeploymentType>().type());
|
||||
if (rv == nullptr && (deployment_type == "dev" || deployment_type == "demo"))
|
||||
rv = resolve_sim_connection(data, account, sec);
|
||||
break;
|
||||
}
|
||||
case api::Venue::VENUE_UNSET:
|
||||
case api::Venue::VENUE_BTS:
|
||||
case api::Venue::VENUE_SIM:
|
||||
case api::Venue::VENUE_SIMICE:
|
||||
rv = resolve_sim_connection(data, account, sec);
|
||||
break;
|
||||
case api::Venue::VENUE_CBOE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::VENUE_ICE:
|
||||
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
rv = nullptr;
|
||||
@@ -156,9 +184,15 @@ void AdminServiceUtils::fill_connections_from_config(bts::api::admin::AdminData&
|
||||
case config::JetFIX::Connection::CBOE:
|
||||
break;
|
||||
case config::JetFIX::Connection::SIM:
|
||||
case config::JetFIX::Connection::SIMICE:
|
||||
connection.mutable_sim_connection();
|
||||
add_connection(admin_data,connection);
|
||||
break;
|
||||
case config::JetFIX::Connection::ICE:
|
||||
connection.mutable_ice_connection()->set_sender_compid(c.sender_compid());
|
||||
add_connection(admin_data,connection);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
for(int i=0;i<admin_data.accounts_size();i++)
|
||||
@@ -240,6 +274,18 @@ const bts::api::admin::CMEAccountData* AdminServiceUtils::get_account_cme_data(c
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bts::api::admin::ICEAccountData* AdminServiceUtils::get_account_ice_data(const bts::api::admin::BTSAccount& account,
|
||||
const bts::api::admin::AdminData& data){
|
||||
if (account.has_exchange_account_data() && account.exchange_account_data().has_ice_account_data())
|
||||
return &(account.exchange_account_data().ice_account_data());
|
||||
else if (has_id(account.parent_account_id())){
|
||||
const bts::api::admin::BTSAccount* parent_account = find_account(data, account.parent_account_id());
|
||||
if (parent_account != nullptr)
|
||||
return get_account_ice_data (*parent_account, data);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bts::api::admin::SIMAccountData* AdminServiceUtils::get_account_sim_data(const bts::api::admin::BTSAccount& account,
|
||||
const bts::api::admin::AdminData& data){
|
||||
if (account.has_exchange_account_data() && account.exchange_account_data().has_sim_account_data())
|
||||
@@ -275,7 +321,16 @@ std::string AdminServiceUtils::find_account_exchange_account (const bts::api::ad
|
||||
rv = cme_account_data->clearing_account();
|
||||
break;
|
||||
}
|
||||
case api::Venue::VENUE_SIM: {
|
||||
case api::Venue::VENUE_ICE:
|
||||
{
|
||||
auto ice_account_data = get_account_ice_data(account, data);
|
||||
if (ice_account_data != nullptr)
|
||||
rv = ice_account_data->clearing_account();
|
||||
break;
|
||||
}
|
||||
case api::Venue::VENUE_SIM:
|
||||
case api::Venue::VENUE_SIMICE:
|
||||
{
|
||||
auto sim_account_data = get_account_sim_data(account, data);
|
||||
if (sim_account_data != nullptr)
|
||||
rv = sim_account_data->clearing_account();
|
||||
@@ -284,8 +339,7 @@ std::string AdminServiceUtils::find_account_exchange_account (const bts::api::ad
|
||||
case api::Venue::VENUE_UNSET:
|
||||
case api::Venue::VENUE_BTS:
|
||||
case api::Venue::VENUE_CBOE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::VENUE_ICE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
out_result.set_is_success(false); out_result.set_error_text("Exchange not supported");
|
||||
@@ -385,6 +439,46 @@ bts::api::orderman::RoutingRecord AdminServiceUtils::get_routing_record(const bt
|
||||
return rv;
|
||||
}
|
||||
switch (sec.exchange()) {
|
||||
case api::Venue::VENUE_ICE:
|
||||
{
|
||||
const bts::api::admin::ICEUserData* ice_user_data = get_user_ice_data(*user_ptr, data);
|
||||
if(ice_user_data==nullptr)
|
||||
{
|
||||
out_result.set_is_success(false);
|
||||
out_result.set_error_text("Could not find ICE data for user");
|
||||
return rv;
|
||||
}
|
||||
const bts::api::admin::ICEAccountData* ice_account_data = get_account_ice_data(*account_ptr, data);
|
||||
if(ice_account_data==nullptr)
|
||||
{
|
||||
out_result.set_is_success(false);
|
||||
out_result.set_error_text("Could not find ICE data for account");
|
||||
return rv;
|
||||
}
|
||||
// check for data corectness
|
||||
if (ice_user_data->operator_id().length() == 0)
|
||||
{
|
||||
out_result.set_is_success(false);
|
||||
out_result.set_error_text("Operator ID is not set");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv.set_session(conn_ptr->name());
|
||||
rv.set_sender_compid(conn_ptr->ice_connection().sender_compid());
|
||||
rv.set_account(ice_account_data->clearing_account());
|
||||
rv.set_operator_id(ice_user_data->operator_id());
|
||||
rv.set_cti_code(ice_account_data->cti());
|
||||
rv.set_customer_or_firm(ice_account_data->origin());
|
||||
rv.set_clearing_firm(ice_account_data->clearing_firm());
|
||||
rv.set_customer_account_ref_id(ice_account_data->customer_account_ref_id());
|
||||
rv.set_account_code(ice_account_data->account_code());
|
||||
rv.set_company_id(std::to_string(ice_user_data->company_id()));
|
||||
rv.set_authorized_trader(ice_user_data->authorized_trader());
|
||||
rv.set_authorized_group(ice_user_data->authorized_group());
|
||||
rv.set_cust_order_handing_inst(ice_user_data->cust_order_handing_inst());
|
||||
|
||||
return rv;
|
||||
}
|
||||
case bts::api::Venue::VENUE_GLBX: {
|
||||
const bts::api::admin::CMEUserData* cme_user_data = get_user_cme_data(*user_ptr, data);
|
||||
if(cme_user_data==nullptr){
|
||||
@@ -435,7 +529,9 @@ bts::api::orderman::RoutingRecord AdminServiceUtils::get_routing_record(const bt
|
||||
rv.set_customer_or_firm(cme_account_data->origin());
|
||||
return rv;
|
||||
}
|
||||
case api::Venue::VENUE_SIM: {
|
||||
case api::Venue::VENUE_SIM:
|
||||
case api::Venue::VENUE_SIMICE:
|
||||
{
|
||||
const bts::api::admin::SIMUserData* sim_user_data = get_user_sim_data(*user_ptr, data);
|
||||
if(sim_user_data==nullptr){
|
||||
out_result.set_is_success(false);
|
||||
@@ -481,8 +577,7 @@ bts::api::orderman::RoutingRecord AdminServiceUtils::get_routing_record(const bt
|
||||
case api::Venue::VENUE_UNSET:
|
||||
case api::Venue::VENUE_BTS:
|
||||
case api::Venue::VENUE_CBOE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::VENUE_ICE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
out_result.set_is_success(false);
|
||||
@@ -629,6 +724,18 @@ const bts::api::admin::CMEUserData* AdminServiceUtils::get_group_cme_data(const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bts::api::admin::ICEUserData* AdminServiceUtils::get_group_ice_data(const bts::api::admin::BTSUserGroup& group,
|
||||
const bts::api::admin::AdminData& data){
|
||||
if (group.has_user_data() && group.user_data().has_exchange_user_data() && group.user_data().exchange_user_data().has_ice_data())
|
||||
return &(group.user_data().exchange_user_data().ice_data());
|
||||
else if (has_id(group.parent_group_id())){
|
||||
const bts::api::admin::BTSUserGroup* parent_group = find_group(data, group.parent_group_id());
|
||||
if (parent_group != nullptr)
|
||||
return get_group_ice_data(*parent_group, data);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bts::api::admin::SIMUserData* AdminServiceUtils::get_group_sim_data(const bts::api::admin::BTSUserGroup& group,
|
||||
const bts::api::admin::AdminData& data){
|
||||
if (group.has_user_data() && group.user_data().has_exchange_user_data() && group.user_data().exchange_user_data().has_sim_data())
|
||||
@@ -759,6 +866,18 @@ const bts::api::admin::CMEUserData* AdminServiceUtils::get_user_cme_data(const b
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bts::api::admin::ICEUserData* AdminServiceUtils::get_user_ice_data(const bts::api::admin::BTSUser& user,
|
||||
const bts::api::admin::AdminData& data){
|
||||
if (user.has_user_data() && user.user_data().has_exchange_user_data() && user.user_data().exchange_user_data().has_ice_data())
|
||||
return &(user.user_data().exchange_user_data().ice_data());
|
||||
else{
|
||||
const bts::api::admin::BTSUserGroup* parent_group = find_group(data, user.parent_group_id());
|
||||
if (parent_group != nullptr)
|
||||
return get_group_ice_data(*parent_group, data);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bts::api::admin::SIMUserData* AdminServiceUtils::get_user_sim_data(const bts::api::admin::BTSUser& user,
|
||||
const bts::api::admin::AdminData& data){
|
||||
if (user.has_user_data() && user.user_data().has_exchange_user_data() && user.user_data().exchange_user_data().has_sim_data())
|
||||
@@ -786,7 +905,16 @@ std::string AdminServiceUtils::find_user_exchange_id (const bts::api::admin::Adm
|
||||
rv = cme_user_data->operator_id();
|
||||
break;
|
||||
}
|
||||
case api::Venue::VENUE_SIM: {
|
||||
case api::Venue::VENUE_ICE:
|
||||
{
|
||||
auto ice_user_data = get_user_ice_data(user, data);
|
||||
if (ice_user_data != nullptr)
|
||||
rv = ice_user_data->operator_id();
|
||||
break;
|
||||
}
|
||||
case api::Venue::VENUE_SIM:
|
||||
case api::Venue::VENUE_SIMICE:
|
||||
{
|
||||
auto sim_user_data = get_user_sim_data(user, data);
|
||||
if (sim_user_data != nullptr)
|
||||
rv = sim_user_data->operator_id();
|
||||
@@ -796,8 +924,7 @@ std::string AdminServiceUtils::find_user_exchange_id (const bts::api::admin::Adm
|
||||
case api::Venue::VENUE_UNSET:
|
||||
case api::Venue::VENUE_BTS:
|
||||
case api::Venue::VENUE_CBOE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::VENUE_ICE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
out_result.set_is_success(false); out_result.set_error_text("Exchange not supported");
|
||||
@@ -805,6 +932,38 @@ std::string AdminServiceUtils::find_user_exchange_id (const bts::api::admin::Adm
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
std::string AdminServiceUtils::find_user_company_id (const bts::api::admin::AdminData& data,
|
||||
const bts::api::admin::BTSUser& user,
|
||||
api::Venue exchange,
|
||||
bts::api::admin::AdminServiceOperationResult& out_result)
|
||||
{
|
||||
out_result.set_is_success(true);
|
||||
std::string rv = "";
|
||||
switch(exchange)
|
||||
{
|
||||
case api::Venue::VENUE_ICE:
|
||||
{
|
||||
auto ice_user_data = get_user_ice_data(user, data);
|
||||
if (ice_user_data != nullptr)
|
||||
rv = std::to_string(ice_user_data->company_id());
|
||||
break;
|
||||
}
|
||||
case api::Venue::VENUE_SIM:
|
||||
case api::Venue::VENUE_SIMICE:
|
||||
case api::Venue::VENUE_GLBX:
|
||||
case api::Venue::VENUE_UNSET:
|
||||
case api::Venue::VENUE_BTS:
|
||||
case api::Venue::VENUE_CBOE:
|
||||
case api::Venue::VENUE_CBOECFE:
|
||||
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
||||
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
||||
out_result.set_is_success(false); out_result.set_error_text("Exchange not supported");
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
std::pair<const bts::api::admin::BTSAccount*, const bts::api::admin::BTSUser*>
|
||||
AdminServiceUtils::find_user_account_matches (const bts::api::admin::AdminData& admin_data,
|
||||
const std::string& connection, const std::string& exchange_account,
|
||||
@@ -815,14 +974,22 @@ AdminServiceUtils::find_user_account_matches (const bts::api::admin::AdminData&
|
||||
auto user_ptrs = users(admin_data, false);
|
||||
for(const bts::api::admin::BTSAccount* account_ptr : account_ptrs){
|
||||
if (account_has_connection(*account_ptr, connection)){
|
||||
if (boost::algorithm::iequals(exchange_account,
|
||||
find_account_exchange_account(admin_data,*account_ptr,exchange,find_account_result)) &&
|
||||
find_account_result.is_success()){
|
||||
for(const bts::api::admin::BTSUser* user_ptr : user_ptrs){
|
||||
if (boost::algorithm::iequals(exchange_user,
|
||||
find_user_exchange_id(admin_data,*user_ptr,exchange,find_user_result)) &&
|
||||
if (boost::algorithm::iequals(exchange_account, find_account_exchange_account(admin_data,*account_ptr,exchange,find_account_result)) &&
|
||||
find_account_result.is_success())
|
||||
{
|
||||
for(const bts::api::admin::BTSUser* user_ptr : user_ptrs)
|
||||
{
|
||||
if (boost::algorithm::iequals(exchange_user,find_user_exchange_id(admin_data,*user_ptr,exchange,find_user_result)) &&
|
||||
find_user_result.is_success())
|
||||
return std::pair<const bts::api::admin::BTSAccount*, const bts::api::admin::BTSUser*>(account_ptr,user_ptr);
|
||||
|
||||
//This code eventually gets called by get_reverse_routing_record(...)
|
||||
//At the ice, they send back the login level tag50 in exec reports which doesn't match any user level tag50s in the exchange_user
|
||||
//so instead we look for the CompanyID (or client_id, tag 109) field here. If this field matches we have a good bet that
|
||||
//the user we find is enough to fulfill the routing record enough to cancel or modify orphaned orders, etc
|
||||
if (boost::algorithm::iequals(exchange_user,find_user_company_id(admin_data,*user_ptr,exchange,find_user_result)) &&
|
||||
find_user_result.is_success())
|
||||
return std::pair<const bts::api::admin::BTSAccount*, const bts::api::admin::BTSUser*>(account_ptr,user_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1045,13 +1212,6 @@ void AdminServiceUtils::set_user_exchange_data(bts::api::admin::BTSUser* user,
|
||||
if (!user->user_data().has_exchange_user_data())
|
||||
user->mutable_user_data()->mutable_exchange_user_data()->CopyFrom(exchange_user_data);
|
||||
}
|
||||
void AdminServiceUtils::set_user_md_entitlement_data(bts::api::admin::BTSUser* user,
|
||||
const bts::api::admin::ExchangeUserMarketDataEntitlementData& exchange_user_md_entitelemnt_data){
|
||||
if (!user->has_user_data())
|
||||
user->mutable_user_data();
|
||||
if (!user->user_data().has_exchange_md_entitlement_data())
|
||||
user->mutable_user_data()->mutable_exchange_md_entitlement_data()->CopyFrom(exchange_user_md_entitelemnt_data);
|
||||
}
|
||||
void AdminServiceUtils::clear_user_accounts (bts::api::admin::BTSUser* user){
|
||||
if(user->has_user_data() && user->user_data().has_account_permissions())
|
||||
user->mutable_user_data()->clear_account_permissions();
|
||||
@@ -1296,6 +1456,7 @@ void AdminServiceUtils::bootstrap_data (bts::api::admin::AdminData& data){
|
||||
auto account_1 = create_account(data, parent_account->id(), std::string("ACC A1"), std::string("description"), true, account_result); account_1->set_is_active(true);
|
||||
auto account_2 = create_account(data, parent_account->id(), std::string("ACC A2"), std::string("description"), true, account_result); account_2->set_is_active(true);
|
||||
auto account_3 = create_account(data, parent_account->id(), std::string("ACC A3"), std::string("description"), true, account_result); account_3->set_is_active(true);
|
||||
auto account_4 = create_account(data, parent_account->id(), std::string("BLUETST"), std::string("description"), true, account_result); account_4->set_is_active(true);
|
||||
create_account(data, parent_account->id(), std::string("ACC A4"), std::string("description"), true, account_result);
|
||||
// add group
|
||||
auto def_group = create_group(data, 0, std::string("default"), result);
|
||||
@@ -1307,7 +1468,6 @@ void AdminServiceUtils::bootstrap_data (bts::api::admin::AdminData& data){
|
||||
auto user_3 = create_user(data, def_group->id(), std::string("bts_3"), std::string("bts_3"), empty, empty, false, license_data, license_entitlements, user_result); user_3->set_is_active(true);
|
||||
//associate users
|
||||
bts::api::admin::UserAccountPermissionUnit permission_unit;
|
||||
permission_unit.mutable_trading_permission()->set_submit_market_orders(true);
|
||||
permission_unit.mutable_trading_permission()->set_has_permissions(true);
|
||||
permission_unit.mutable_admin_permission()->set_has_permissions(true);
|
||||
bts::api::admin::UserAccountPermissions account_permissions;
|
||||
@@ -1315,6 +1475,7 @@ void AdminServiceUtils::bootstrap_data (bts::api::admin::AdminData& data){
|
||||
account_permissions.mutable_account_permissions()->insert(google::protobuf::MapPair<uint32_t, bts::api::admin::UserAccountPermissionUnit>(account_1->id(), permission_unit));
|
||||
account_permissions.mutable_account_permissions()->insert(google::protobuf::MapPair<uint32_t, bts::api::admin::UserAccountPermissionUnit>(account_2->id(), permission_unit));
|
||||
account_permissions.mutable_account_permissions()->insert(google::protobuf::MapPair<uint32_t, bts::api::admin::UserAccountPermissionUnit>(account_3->id(), permission_unit));
|
||||
account_permissions.mutable_account_permissions()->insert(google::protobuf::MapPair<uint32_t, bts::api::admin::UserAccountPermissionUnit>(account_4->id(), permission_unit));
|
||||
set_user_accounts(user_1, account_permissions);
|
||||
set_user_accounts(user_2, account_permissions);
|
||||
set_user_accounts(user_3, account_permissions);
|
||||
@@ -1324,6 +1485,12 @@ void AdminServiceUtils::bootstrap_data (bts::api::admin::AdminData& data){
|
||||
exchange_account_data.mutable_cme_account_data()->set_cti(bts::api::orderman::CTICode::CTI_CODE_CTI_CODE1);
|
||||
exchange_account_data.mutable_cme_account_data()->set_origin(bts::api::orderman::CustomerOrFirm::CUSTOMER_OR_FIRM_FIRM);
|
||||
exchange_account_data.mutable_cme_account_data()->set_clearing_account(parent_account->name());
|
||||
|
||||
exchange_account_data.mutable_ice_account_data()->set_cti(bts::api::orderman::CTICode::CTI_CODE_UNDEFINED);
|
||||
exchange_account_data.mutable_ice_account_data()->set_origin(bts::api::orderman::CustomerOrFirm::CUSTOMER_OR_FIRM_FIRM);
|
||||
exchange_account_data.mutable_ice_account_data()->set_clearing_account(parent_account->name());
|
||||
exchange_account_data.mutable_ice_account_data()->set_clearing_firm("649");
|
||||
|
||||
exchange_account_data.mutable_sim_account_data()->set_cti(bts::api::orderman::CTICode::CTI_CODE_CTI_CODE1);
|
||||
exchange_account_data.mutable_sim_account_data()->set_origin(bts::api::orderman::CustomerOrFirm::CUSTOMER_OR_FIRM_FIRM);
|
||||
exchange_account_data.mutable_sim_account_data()->set_clearing_account(parent_account->name());
|
||||
@@ -1331,33 +1498,87 @@ void AdminServiceUtils::bootstrap_data (bts::api::admin::AdminData& data){
|
||||
|
||||
|
||||
exchange_account_data.mutable_cme_account_data()->set_clearing_account(account_1->name());
|
||||
exchange_account_data.mutable_ice_account_data()->set_clearing_account(account_1->name());
|
||||
exchange_account_data.mutable_sim_account_data()->set_clearing_account(account_1->name());
|
||||
set_account_exchange_data(account_1, exchange_account_data);
|
||||
|
||||
exchange_account_data.mutable_cme_account_data()->set_clearing_account(account_2->name());
|
||||
exchange_account_data.mutable_ice_account_data()->set_clearing_account(account_2->name());
|
||||
exchange_account_data.mutable_sim_account_data()->set_clearing_account(account_2->name());
|
||||
set_account_exchange_data(account_2, exchange_account_data);
|
||||
|
||||
exchange_account_data.mutable_cme_account_data()->set_clearing_account(account_3->name());
|
||||
exchange_account_data.mutable_ice_account_data()->set_clearing_account(account_3->name());
|
||||
exchange_account_data.mutable_sim_account_data()->set_clearing_account(account_3->name());
|
||||
set_account_exchange_data(account_3, exchange_account_data);
|
||||
|
||||
exchange_account_data.mutable_ice_account_data()->set_clearing_account(account_4->name());
|
||||
set_account_exchange_data(account_4, exchange_account_data);
|
||||
|
||||
|
||||
// add cme and sim user data
|
||||
bts::api::admin::ExchangeUserData exchange_user_data;
|
||||
exchange_user_data.mutable_cme_data()->set_operator_id("op_id_" + user_1->name());
|
||||
exchange_user_data.mutable_cme_data()->set_location("us,nc");
|
||||
|
||||
exchange_user_data.mutable_ice_data()->set_operator_id("op_id_" + user_1->name());
|
||||
exchange_user_data.mutable_ice_data()->set_company_id(51251);
|
||||
exchange_user_data.mutable_ice_data()->set_authorized_trader("bluetrd-fx");
|
||||
exchange_user_data.mutable_ice_data()->set_authorized_group("Group");
|
||||
exchange_user_data.mutable_ice_data()->set_password("Starts123");
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_direct_electronic_access(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_trading_capacity(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_liquidity_provision(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_commodity_deriv_indicator(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_investment_decision(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_execution_decision(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_client_id_code(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_id(1);
|
||||
|
||||
exchange_user_data.mutable_sim_data()->set_operator_id("op_id_" + user_1->name());
|
||||
exchange_user_data.mutable_sim_data()->set_location("us,nc");
|
||||
set_user_exchange_data(user_1, exchange_user_data);
|
||||
|
||||
exchange_user_data.mutable_cme_data()->set_operator_id("op_id_" + user_2->name());
|
||||
exchange_user_data.mutable_cme_data()->set_location("us,nc");
|
||||
|
||||
exchange_user_data.mutable_ice_data()->set_operator_id("op_id_" + user_2->name());
|
||||
exchange_user_data.mutable_ice_data()->set_company_id(51251);
|
||||
exchange_user_data.mutable_ice_data()->set_authorized_trader("bluetrd-fx");
|
||||
exchange_user_data.mutable_ice_data()->set_authorized_group("Group");
|
||||
exchange_user_data.mutable_ice_data()->set_password("Starts123");
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_direct_electronic_access(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_trading_capacity(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_liquidity_provision(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_commodity_deriv_indicator(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_investment_decision(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_execution_decision(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_client_id_code(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_id(1);
|
||||
|
||||
|
||||
exchange_user_data.mutable_sim_data()->set_operator_id("op_id_" + user_2->name());
|
||||
exchange_user_data.mutable_sim_data()->set_location("us,nc");
|
||||
set_user_exchange_data(user_2, exchange_user_data);
|
||||
|
||||
exchange_user_data.mutable_cme_data()->set_operator_id("op_id_" + user_3->name());
|
||||
exchange_user_data.mutable_cme_data()->set_location("us,nc");
|
||||
|
||||
exchange_user_data.mutable_ice_data()->set_operator_id("op_id_" + user_3->name());
|
||||
exchange_user_data.mutable_ice_data()->set_company_id(51251);
|
||||
exchange_user_data.mutable_ice_data()->set_authorized_trader("bluetrd-fx");
|
||||
exchange_user_data.mutable_ice_data()->set_authorized_group("Group");
|
||||
exchange_user_data.mutable_ice_data()->set_password("Starts123");
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_direct_electronic_access(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_trading_capacity(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_liquidity_provision(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_commodity_deriv_indicator(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_investment_decision(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_execution_decision(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_client_id_code(-1);
|
||||
exchange_user_data.mutable_ice_data()->set_mifid_id(1);
|
||||
|
||||
|
||||
exchange_user_data.mutable_sim_data()->set_operator_id("op_id_" + user_3->name());
|
||||
exchange_user_data.mutable_sim_data()->set_location("us,nc");
|
||||
set_user_exchange_data(user_3, exchange_user_data);
|
||||
@@ -1399,6 +1620,13 @@ void AdminServiceUtils::bootstrap_data (bts::api::admin::AdminData& data){
|
||||
add_security_clip_sizes_to_account(account_1, api::Venue::VENUE_GLBX, api::SecurityType::SECURITYTYPE_SPREAD,100);
|
||||
add_security_clip_sizes_to_account(account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_FUTURE,100);
|
||||
add_security_clip_sizes_to_account(account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_SPREAD,100);
|
||||
|
||||
//ICE limits
|
||||
add_product_position_limits(account_4, api::Venue::VENUE_ICE, api::SecurityType::SECURITYTYPE_FUTURE,50000);
|
||||
add_product_position_limits(account_4, api::Venue::VENUE_ICE, api::SecurityType::SECURITYTYPE_SPREAD,50000);
|
||||
add_security_clip_sizes_to_account(account_4, api::Venue::VENUE_ICE, api::SecurityType::SECURITYTYPE_FUTURE,50);
|
||||
add_security_clip_sizes_to_account(account_4, api::Venue::VENUE_ICE, api::SecurityType::SECURITYTYPE_SPREAD,50);
|
||||
|
||||
}
|
||||
bool AdminServiceUtils::has_id (uint32_t id){return id>0;}
|
||||
bool AdminServiceUtils::is_symbol_set (const std::string& symbol){
|
||||
|
||||
@@ -35,6 +35,10 @@ public:
|
||||
const AdminData& data,
|
||||
const BTSAccount& account,
|
||||
const api::Security& sec);
|
||||
static const ExchangeConnection* resolve_ice_connection(
|
||||
const AdminData& data,
|
||||
const BTSAccount& account,
|
||||
const api::Security& sec);
|
||||
static const ExchangeConnection* resolve_sim_connection(
|
||||
const AdminData& data,
|
||||
const BTSAccount& account,
|
||||
@@ -85,6 +89,8 @@ public:
|
||||
// if needed)
|
||||
static const CMEAccountData* get_account_cme_data(const BTSAccount& account,
|
||||
const AdminData& data);
|
||||
static const ICEAccountData* get_account_ice_data(const BTSAccount& account,
|
||||
const AdminData& data);
|
||||
static const SIMAccountData* get_account_sim_data(const BTSAccount& account,
|
||||
const AdminData& data);
|
||||
// returns true if an account has a connection
|
||||
@@ -156,6 +162,8 @@ public:
|
||||
// travels up the group tree until it finds a populated cme data
|
||||
static const CMEUserData* get_group_cme_data(const BTSUserGroup& group,
|
||||
const AdminData& data);
|
||||
static const ICEUserData* get_group_ice_data(const BTSUserGroup& group,
|
||||
const AdminData& data);
|
||||
static const SIMUserData* get_group_sim_data(const BTSUserGroup& group,
|
||||
const AdminData& data);
|
||||
static const UserAccountPermissions* const get_group_user_permissions (
|
||||
@@ -190,6 +198,8 @@ public:
|
||||
static uint32_t find_max_user_id (const AdminData& data);
|
||||
static const CMEUserData* get_user_cme_data(const BTSUser& user,
|
||||
const AdminData& data);
|
||||
static const ICEUserData* get_user_ice_data(const BTSUser& user,
|
||||
const AdminData& data);
|
||||
static const SIMUserData* get_user_sim_data(const BTSUser& user,
|
||||
const AdminData& data);
|
||||
// finds the "exchange user" (ex: "operator_id" at CME or "authorized_trader"
|
||||
@@ -199,6 +209,12 @@ public:
|
||||
const BTSUser& user,
|
||||
api::Venue exchange,
|
||||
AdminServiceOperationResult& out_result);
|
||||
static std::string find_user_company_id (
|
||||
const AdminData& data,
|
||||
const BTSUser& user,
|
||||
api::Venue exchange,
|
||||
AdminServiceOperationResult& out_result);
|
||||
|
||||
static std::pair<const BTSAccount*, const BTSUser*>
|
||||
find_user_account_matches (const AdminData& admin_data,
|
||||
const std::string& connection,
|
||||
@@ -264,8 +280,6 @@ public:
|
||||
static void set_user_exchange_data(
|
||||
BTSUser* user,
|
||||
const ExchangeUserData& exchange_user_data);
|
||||
static void set_user_md_entitlement_data(BTSUser* user,
|
||||
const ExchangeUserMarketDataEntitlementData&);
|
||||
static void clear_user_accounts (BTSUser* user);
|
||||
static void set_user_accounts (BTSUser* user,
|
||||
const UserAccountPermissions& user_account_permissions);
|
||||
|
||||
@@ -55,11 +55,12 @@ message BTSUser{
|
||||
string name = 30;
|
||||
string password = 40;
|
||||
string full_name = 42;
|
||||
string company = 44;
|
||||
string company = 44;
|
||||
bool is_active = 50;
|
||||
bool can_create = 55;
|
||||
LicenseData license_data = 60; //unused
|
||||
LicenseEntitlements license_entitlements = 70; //unused
|
||||
LicenseData license_data = 60;
|
||||
LicenseEntitlements license_entitlements = 70;
|
||||
|
||||
BTSUserDerivableData user_data = 80;
|
||||
}
|
||||
|
||||
@@ -76,7 +77,7 @@ message BTSUserDerivableData{
|
||||
// b. else its overridden at the user level
|
||||
UserAccountPermissions account_permissions = 70;
|
||||
ExchangeUserData exchange_user_data = 80;
|
||||
ExchangeUserMarketDataEntitlementData exchange_md_entitlement_data = 90;
|
||||
reserved 90; reserved "exchange_md_entitlement_data"; //ExchangeUserMarketDataEntitlementData exchange_md_entitlement_data = 90;
|
||||
}
|
||||
|
||||
message LicenseData{
|
||||
@@ -91,21 +92,22 @@ message LicenseEntitlements{
|
||||
bool spreader = 30;
|
||||
}
|
||||
|
||||
message AlgoTradingPermissionsUnit{
|
||||
bool submit_iceberg_orders = 10; //unused
|
||||
bool submit_time_box_orders = 20; //unused
|
||||
bool submit_spreader_orders = 30; //unused
|
||||
}
|
||||
// message AlgoTradingPermissionsUnit{
|
||||
// bool submit_iceberg_orders = 10; //unused
|
||||
// bool submit_time_box_orders = 20; //unused
|
||||
// bool submit_spreader_orders = 30; //unused
|
||||
// }
|
||||
|
||||
message TradingPermissionUnit{
|
||||
reserved 10; reserved "submit_market_orders"; //bool submit_market_orders = 10; //unused
|
||||
reserved 20; reserved "submit_gtc_orders"; //bool submit_gtc_orders = 20; //unused
|
||||
reserved 30; reserved "algo_trading_permission"; //AlgoTradingPermissionsUnit algo_trading_permission = 30; //unused
|
||||
|
||||
bool has_permissions = 5;
|
||||
bool submit_market_orders = 10; //unused
|
||||
bool submit_gtc_orders = 20; //unused
|
||||
AlgoTradingPermissionsUnit algo_trading_permission = 30; //unused
|
||||
}
|
||||
|
||||
message AdminPermissionUnit{
|
||||
// TODO: needs to be more ellaborate (account writing,
|
||||
// TODO: needs to be more ellaborate (account writing,
|
||||
// reading etc, routing etc)
|
||||
bool has_permissions = 10;
|
||||
bool has_md_permissions = 20;
|
||||
@@ -119,15 +121,15 @@ message UserAccountPermissionUnit{
|
||||
|
||||
message UserAccountPermissions{
|
||||
//uint32 = account_id
|
||||
map<uint32, UserAccountPermissionUnit> account_permissions = 10;
|
||||
map<uint32, UserAccountPermissionUnit> account_permissions = 10;
|
||||
}
|
||||
|
||||
// unused now
|
||||
message UserSecurityTradingLimit{
|
||||
SecurityScope security = 10;
|
||||
uint32 clip_size = 20;
|
||||
bool can_trade = 30;
|
||||
}
|
||||
// // unused now
|
||||
// message UserSecurityTradingLimit{
|
||||
// SecurityScope security = 10;
|
||||
// uint32 clip_size = 20;
|
||||
// bool can_trade = 30;
|
||||
// }
|
||||
|
||||
/************************************************************************/
|
||||
/********************************BTS Account*****************************/
|
||||
@@ -152,7 +154,7 @@ message BTSAccount{
|
||||
AccountLossLimit account_loss_limit = 130;
|
||||
}
|
||||
|
||||
message RiskLimitEnforcement{
|
||||
message RiskLimitEnforcement{
|
||||
bool product_limit_in_net_terms = 10;
|
||||
}
|
||||
|
||||
@@ -203,23 +205,22 @@ message AccountLossLimit{
|
||||
message CMEMicData{
|
||||
api.CMEMics mic=10;
|
||||
bool enabled=20;
|
||||
// there are other things here
|
||||
// there are other things here
|
||||
}
|
||||
|
||||
message ICEMicData{
|
||||
api.CMEMics mic=10;
|
||||
api.ICEMics mic=10;
|
||||
bool enabled=20;
|
||||
}
|
||||
|
||||
message ExchangeUserMarketDataEntitlementData{
|
||||
CMEUserMarketDataEntitlementData cme_data = 10;
|
||||
ICEUserMarketDataEntitlementData ice_data = 20;
|
||||
}
|
||||
|
||||
message ExchangeUserData{
|
||||
CMEUserData cme_data = 10;
|
||||
ICEUserData ice_data = 20;
|
||||
SIMUserData sim_data = 30;
|
||||
|
||||
enum AdminDisplay { All = 0; MD = 1; Routing = 2; None = 100; }
|
||||
AdminDisplay admin_display_flag = 120;
|
||||
}
|
||||
|
||||
message ExchangeAccountData{
|
||||
@@ -228,9 +229,6 @@ message ExchangeAccountData{
|
||||
SIMAccountData sim_account_data = 30;
|
||||
}
|
||||
|
||||
message MarketDataEntitlement{
|
||||
bool can_view = 10;
|
||||
}
|
||||
|
||||
message ExchangeConnection{
|
||||
uint32 id = 10;
|
||||
@@ -273,19 +271,19 @@ message CMEMSGWConnection{
|
||||
uint32 market_segment_id = 60;
|
||||
}
|
||||
|
||||
message CMEAccountData{
|
||||
// should perhaps be an enum
|
||||
message CMEAccountData {
|
||||
reserved 30; reserved "takeup_member_code"; //string takeup_member_code = 30;
|
||||
reserved 50; reserved "direct_electronic_access"; //string direct_electronic_access = 50;
|
||||
reserved 60; reserved "trading_capacity"; //string trading_capacity = 60;
|
||||
reserved 70; reserved "liquidity_provision"; //string liquidity_provision = 70;
|
||||
reserved 80; reserved "commodity_derivative_indicator"; //string commodity_derivative_indicator = 80;
|
||||
reserved 90; reserved "investment_decision_id"; //string investment_decision_id = 90;
|
||||
reserved 100; reserved "execution_decision_id"; //string execution_decision_id = 100;
|
||||
reserved 110; reserved "client_id"; //string client_id = 110;
|
||||
|
||||
api.orderman.CTICode cti = 10;
|
||||
api.orderman.CustomerOrFirm origin = 20;
|
||||
string takeup_member_code = 30;
|
||||
string clearing_account = 40;
|
||||
string direct_electronic_access = 50;
|
||||
string trading_capacity = 60;
|
||||
string liquidity_provision = 70;
|
||||
string commodity_derivative_indicator = 80;
|
||||
string investment_decision_id = 90;
|
||||
string execution_decision_id = 100;
|
||||
string client_id = 110;
|
||||
map<string, string> misc_tags = 120;
|
||||
}
|
||||
|
||||
@@ -308,21 +306,22 @@ enum DisplayDesignation
|
||||
}
|
||||
|
||||
message CMEUserData{
|
||||
reserved 20; reserved "ats_operator_id"; //string ats_operator_id = 20;
|
||||
reserved 40; reserved "text_a"; //string text_a = 40;
|
||||
reserved 50; reserved "text_b"; //string text_b = 50;
|
||||
reserved 80; reserved "max_order_rate_per_connection"; //string max_order_rate_per_connection = 80;
|
||||
//enum AdminDisplay { All = 0; MD = 1; Routing = 2; None = 100; }
|
||||
reserved 120; reserved "admin_display_flag"; //AdminDisplay admin_display_flag = 120;
|
||||
repeated CMEMicData md_permissions = 1000;
|
||||
|
||||
string operator_id = 10;
|
||||
string ats_operator_id = 20;
|
||||
string smp_id = 30;
|
||||
string text_a = 40;
|
||||
string text_b = 50;
|
||||
map<string, string> misc_tags = 60;
|
||||
string smp_instruction = 70;
|
||||
string max_order_rate_per_connection = 80;
|
||||
|
||||
string location = 90;
|
||||
ProfessionalDesignation pro_nonpro = 100;
|
||||
DisplayDesignation display_nondisplay = 110;
|
||||
|
||||
enum AdminDisplay { All = 0; MD = 1; Routing = 2; None = 100; }
|
||||
AdminDisplay admin_display_flag = 120;
|
||||
repeated CMEMicData md_permissions = 1000;
|
||||
}
|
||||
|
||||
message SIMUserData {
|
||||
@@ -330,58 +329,67 @@ message SIMUserData {
|
||||
string location = 90;
|
||||
}
|
||||
|
||||
message CMEUserMarketDataEntitlementData{
|
||||
MarketDataEntitlement cbot_entitlement = 10;
|
||||
MarketDataEntitlement cme_entitlement = 20;
|
||||
MarketDataEntitlement nymex_entitlement = 30;
|
||||
MarketDataEntitlement bmandf_entitlement = 40;
|
||||
MarketDataEntitlement comex_entitlement = 50;
|
||||
MarketDataEntitlement cme_europe_entitlement = 60;
|
||||
}
|
||||
|
||||
/********************************ICE Data*********************************/
|
||||
|
||||
message ICEConnection{
|
||||
string authorized_member_id = 10;
|
||||
string sender_company_id = 20;
|
||||
string sender_sub_id = 30;
|
||||
string session_id = 40;
|
||||
string session_password = 50;
|
||||
string host_ip = 60;
|
||||
string port = 70;
|
||||
string default_routing_trader = 80;
|
||||
string routing_trader_password = 90;
|
||||
int32 max_order_rate = 100;
|
||||
message ICEConnection {
|
||||
string sender_compid = 10;
|
||||
}
|
||||
|
||||
message ICEAccountData{
|
||||
string nybit_house = 10;
|
||||
int32 wce_house = 20;
|
||||
string clearing_account_override = 30;
|
||||
bool direct_electronic_access = 40;
|
||||
string trading_capacity = 50;
|
||||
bool liquidity_provision = 60;
|
||||
bool commodity_derivative_indicator = 70;
|
||||
string investment_decision_id = 80;
|
||||
string execution_decision_id = 90;
|
||||
string client_id = 100;
|
||||
string mfid_id = 110;
|
||||
message ICEAccountData {
|
||||
reserved 10; reserved "nybit_house"; //string nybit_house = 10;
|
||||
reserved 20; reserved "wce_house"; //int32 wce_house = 20;
|
||||
reserved 30; reserved "clearing_account_override"; //string clearing_account_override = 30;
|
||||
reserved 40; reserved "direct_electronic_access"; //bool direct_electronic_access = 40;
|
||||
reserved 50; reserved "trading_capacity"; //string trading_capacity = 50;
|
||||
reserved 60; reserved "liquidity_provision"; //bool liquidity_provision = 60;
|
||||
reserved 70; reserved "commodity_derivative_indicator"; //bool commodity_derivative_indicator = 70;
|
||||
reserved 80; reserved "investment_decision_id"; //string investment_decision_id = 80;
|
||||
reserved 90; reserved "execution_decision_id"; //string execution_decision_id = 90;
|
||||
reserved 100; reserved "client_id"; //string client_id = 100;
|
||||
reserved 110; reserved "mfid_id"; //string mfid_id = 110;
|
||||
|
||||
api.orderman.CTICode cti = 3;
|
||||
api.orderman.CustomerOrFirm origin = 5;
|
||||
string clearing_firm = 200;
|
||||
string clearing_account = 210;
|
||||
string customer_account_ref_id = 220;
|
||||
string account_code = 230;
|
||||
map<string, string> misc_tags = 500;
|
||||
}
|
||||
|
||||
message ICEUserData{
|
||||
string authorized_trader = 10;
|
||||
string memo_field = 20;
|
||||
string text_b = 30;
|
||||
uint32 max_order_rate = 40;
|
||||
}
|
||||
message ICEUserData {
|
||||
reserved 20; reserved "memo_field"; //string memo_field = 20;
|
||||
reserved 30; reserved "text_b"; //string text_b = 30;
|
||||
reserved 40; reserved "max_order_rate"; //uint32 max_order_rate = 40;
|
||||
|
||||
message ICEUserMarketDataEntitlementData{
|
||||
int32 company_id = 3; //tag 109 clientid
|
||||
string operator_id = 5; //tag 50
|
||||
string authorized_trader = 10; //tag 553 user_name
|
||||
string authorized_group = 15; //tag 553 user_name
|
||||
string password = 21; //tag 96 raw data
|
||||
string cust_order_handing_inst = 25;
|
||||
|
||||
//mifid
|
||||
int32 mifid_direct_electronic_access = 500;
|
||||
int32 mifid_trading_capacity = 510;
|
||||
int32 mifid_liquidity_provision = 520;
|
||||
int32 mifid_commodity_deriv_indicator = 530;
|
||||
int64 mifid_investment_decision = 540;
|
||||
int64 mifid_execution_decision = 550;
|
||||
int64 mifid_client_id_code = 560;
|
||||
int64 mifid_id = 570;
|
||||
|
||||
map<string, string> misc_tags = 60;
|
||||
ProfessionalDesignation pro_nonpro = 100;
|
||||
DisplayDesignation display_nondisplay = 110;
|
||||
|
||||
repeated ICEMicData md_permissions = 1000;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Order Auxiliary Service ////////////////////////////////
|
||||
|
||||
message OrdersSummaryUnit{
|
||||
message OrdersSummaryUnit{
|
||||
string account = 10;
|
||||
string user = 20;
|
||||
uint32 total_orders = 30;
|
||||
@@ -392,11 +400,11 @@ message OrdersSummary{
|
||||
}
|
||||
message OrderSummaryRequest{
|
||||
}
|
||||
// top level orders that have account
|
||||
// top level orders that have account
|
||||
// and user that are present here, will
|
||||
// be cancelled. wild cards are not
|
||||
// supported.
|
||||
message OrderCancelRequest{
|
||||
message OrderCancelRequest{
|
||||
repeated string accounts = 10;
|
||||
repeated string users = 20;
|
||||
}
|
||||
@@ -432,7 +440,7 @@ message AccountCreateAPIArgument{
|
||||
string creator_user = 40;
|
||||
}
|
||||
message AccountUpdateAPIArgument{
|
||||
BTSAccount complete_data=10;
|
||||
BTSAccount complete_data=10;
|
||||
}
|
||||
message UserCreateAPIArgument{
|
||||
uint32 parent_group_id = 20;
|
||||
@@ -476,7 +484,7 @@ service AdminService {
|
||||
// users
|
||||
rpc create_user(UserCreateAPIArgument) returns (AdminServiceCreateEntityResult);
|
||||
rpc update_user(UserUpdateAPIArgument) returns (AdminServiceOperationResult);
|
||||
rpc delete_user(IDAPIArgument) returns (AdminServiceOperationResult);
|
||||
rpc delete_user(IDAPIArgument) returns (AdminServiceOperationResult);
|
||||
// subscription
|
||||
rpc admin_data(bts.api.VoidMessage) returns (stream AdminData);
|
||||
rpc get_admin_data(bts.api.VoidMessage) returns (AdminData);
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
syntax="proto3";
|
||||
package bts.history;
|
||||
option csharp_namespace="bts.history";
|
||||
option cc_enable_arenas=true;
|
||||
import "lib/api/apioptions.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
|
||||
message Slice {
|
||||
google.protobuf.Timestamp begin = 10;
|
||||
google.protobuf.Timestamp end = 20;
|
||||
uint32 buy_volume = 30;
|
||||
double avg_buy_price = 40;
|
||||
uint32 sell_volume = 50;
|
||||
double avg_sell_price = 60;
|
||||
}
|
||||
message Slices {
|
||||
repeated Slice slice_vec = 10;
|
||||
}
|
||||
message SliceDistribution {
|
||||
google.protobuf.Timestamp begin = 10;
|
||||
google.protobuf.Timestamp end = 20;
|
||||
double volume_mean = 30;
|
||||
double volume_variance = 40;
|
||||
double price_mean = 50;
|
||||
double price_variance = 60;
|
||||
}
|
||||
message TradingDistribution {
|
||||
double volume_mean = 10;
|
||||
double volume_variance = 20;
|
||||
double volume_skewness = 30;
|
||||
double price_mean = 40;
|
||||
double price_variance = 50;
|
||||
double price_skewness = 60;
|
||||
repeated SliceDistribution slices = 100;
|
||||
}
|
||||
|
||||
message SlicesQuery {
|
||||
string security_desc = 10;
|
||||
google.protobuf.Timestamp begin = 20;
|
||||
google.protobuf.Timestamp end = 30;
|
||||
google.protobuf.Duration dt = 40;
|
||||
}
|
||||
message TradingDistributionQuery {
|
||||
string security_desc = 10;
|
||||
google.protobuf.Timestamp begin = 20;
|
||||
google.protobuf.Timestamp end = 30;
|
||||
google.protobuf.Duration dt = 40;
|
||||
}
|
||||
|
||||
service HistoricalDataService {
|
||||
rpc get_trading_slices(SlicesQuery) returns (Slices);
|
||||
rpc get_trading_distribution (TradingDistributionQuery) returns (TradingDistribution);
|
||||
}
|
||||
@@ -105,11 +105,6 @@ message CustomOrderDefinition
|
||||
ScratchOrderDefinition scratch = 31;
|
||||
ProRataOrderDefinition prorata = 32;
|
||||
|
||||
TWAPOrderDefinition twap = 100;
|
||||
VWAPOrderDefinition vwap = 101;
|
||||
POVOrderDefinition pov = 102;
|
||||
ArrivalPriceOrderDefinition arrival = 103;
|
||||
|
||||
DynamicOrderDefinition dynamic = 1000;
|
||||
}
|
||||
}
|
||||
@@ -235,89 +230,6 @@ message ProRataOrderDefinition {
|
||||
CustomOrderDefinition hedge = 20;
|
||||
CustomOrderDefinition overfill_hedge = 30;
|
||||
}
|
||||
|
||||
message OrderDuration {
|
||||
//default = 0, when to start the order, 0 = immediately
|
||||
google.protobuf.Timestamp start = 10;
|
||||
oneof end
|
||||
{
|
||||
//when to conclude
|
||||
google.protobuf.Timestamp end_timestamp = 20;
|
||||
//alternative to end_time, minutes from start time at which to stop
|
||||
uint32 duration_in_minutes = 30;
|
||||
}
|
||||
//default = 60
|
||||
uint32 discretization_interval_in_seconds = 40;
|
||||
// default = 1, time in periods which to let unexecuted size remain
|
||||
// 0 means unexecuted size must be resolved (paid up) by end of initial period-- this means orders can only work within their period
|
||||
// 1 means unexecuted size must be resolved (paid up) by end of next period-- this establishes two tracks: 'tactical' and 'aggressive'
|
||||
// orders start in the tactical track and are moved to the aggressive once they work beyond their slippage thresh
|
||||
// 2...etc
|
||||
uint32 tactical_schedule_slippage = 50;
|
||||
}
|
||||
message OrderAggression {
|
||||
// default = 0.0, 0.0 - 99.99 be no more than X% of the market, 0.0 means no cap
|
||||
double max_participation_pct = 10;
|
||||
// default = 0.0, price at which you will take liquidity regardless of other parameters, 0.0 means there is no iwouldprice
|
||||
double i_would_price = 20;
|
||||
// default = 0.0, risk neutral, -1.0 to 1.0. nondimensional parameter. -1 is completely risk averse, 1 is risk seeking
|
||||
// this has the net effect of tilting Arrival and VWAP schedules to do more earlier the more negative the parameter
|
||||
// Constant * lambda in Almgren 2000; Konishi 2002
|
||||
double risk_threshold = 30;
|
||||
}
|
||||
message VolumeDistribution {
|
||||
// default = 20, historical volume distribution time horizon
|
||||
uint32 volume_time_horizon_days = 10;
|
||||
|
||||
// default = 0.0 means use historical mean, another value overrides the computed volume mean
|
||||
double volume_mean_override = 15;
|
||||
// default = 0.0 means use historical variance, another value overrides the computed volume variance
|
||||
double volume_variance_override = 20;
|
||||
}
|
||||
message PriceDistribution {
|
||||
// default = 5 biz, 7 cal (weekly), historical price distribution time horizon
|
||||
uint32 price_time_horizon_days = 10;
|
||||
|
||||
// default = 0.0 means use historical mean, another value overrides the computed price mean
|
||||
double price_mean_override = 15;
|
||||
// default = 0.0 means use historical variance, another value overrides the computed price variance
|
||||
double price_variance_override = 20;
|
||||
}
|
||||
|
||||
message TWAPOrderDefinition {
|
||||
OrderDuration duration = 10;
|
||||
OrderAggression aggression = 20;
|
||||
|
||||
CustomOrderDefinition tactical_child = 200;
|
||||
CustomOrderDefinition aggressive_child = 210;
|
||||
}
|
||||
message VWAPOrderDefinition {
|
||||
OrderDuration duration = 10;
|
||||
OrderAggression aggression = 20;
|
||||
VolumeDistribution volume_distribution = 30;
|
||||
PriceDistribution price_distribution = 40;
|
||||
|
||||
CustomOrderDefinition tactical_child = 200;
|
||||
CustomOrderDefinition aggressive_child = 210;
|
||||
}
|
||||
message POVOrderDefinition {
|
||||
double min_participation_pct = 10;
|
||||
OrderDuration duration = 20;
|
||||
OrderAggression aggression = 30;
|
||||
|
||||
CustomOrderDefinition tactical_child = 200;
|
||||
CustomOrderDefinition aggressive_child = 210;
|
||||
}
|
||||
message ArrivalPriceOrderDefinition {
|
||||
OrderDuration duration = 10;
|
||||
OrderAggression aggression = 20;
|
||||
VolumeDistribution volume_distribution = 30;
|
||||
PriceDistribution price_distribution = 40;
|
||||
|
||||
CustomOrderDefinition tactical_child = 200;
|
||||
CustomOrderDefinition aggressive_child = 210;
|
||||
}
|
||||
|
||||
message DynamicOrderDefinition {
|
||||
string dynamic_order_type = 1;
|
||||
map<string, DynamicOrderParam> order_params = 2;
|
||||
@@ -374,11 +286,6 @@ message OrderState {
|
||||
ScratchOrderState scratch = 32;
|
||||
ProRataOrderState prorata = 33;
|
||||
|
||||
TWAPOrderState twap = 100;
|
||||
VWAPOrderState vwap = 101;
|
||||
POVOrderState pov = 102;
|
||||
ArrivalPriceOrderState arrival = 103;
|
||||
|
||||
DynamicOrderState dynamic = 255; // do not use anything bigger than 255, or things will break
|
||||
}
|
||||
}
|
||||
@@ -402,6 +309,13 @@ message Fill {
|
||||
FILL_KIND_SOD = 2;
|
||||
}
|
||||
FillKind fill_kind = 10;
|
||||
|
||||
enum FillStatus {
|
||||
FILL_STATUS_ACTIVE = 0;
|
||||
FILL_STATUS_CORRECTED = 1;
|
||||
FILL_STATUS_BUSTED = 2;
|
||||
}
|
||||
FillStatus fill_status = 20;
|
||||
}
|
||||
|
||||
enum OrderSubType {
|
||||
@@ -419,6 +333,16 @@ message RoutingRecord {
|
||||
string smp_id = 6 ;
|
||||
SelfMatchPreventionInstruction smp_instruction = 7;
|
||||
string location = 8;
|
||||
|
||||
string sender_compid = 15;
|
||||
string clearing_firm = 20;
|
||||
string customer_account_ref_id = 25;
|
||||
string account_code = 30;
|
||||
string company_id = 45;
|
||||
string authorized_trader = 50;
|
||||
string authorized_group = 60;
|
||||
string cust_order_handing_inst = 70;
|
||||
string order_server_id = 200;
|
||||
}
|
||||
|
||||
message NativeOrderState {
|
||||
@@ -459,10 +383,6 @@ message ProRataOrderState {}
|
||||
message DynamicOrderState {}
|
||||
message QueueHolderState {}
|
||||
message SplitterOrderState {}
|
||||
message TWAPOrderState {}
|
||||
message VWAPOrderState {}
|
||||
message POVOrderState {}
|
||||
message ArrivalPriceOrderState {}
|
||||
|
||||
enum OrderStatus {
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
|
||||
|
||||
#define URDL_HEADER_ONLY 1
|
||||
#define URDL_DISALE_SSL 1
|
||||
#include <urdl/url.hpp>
|
||||
@@ -905,3 +906,4 @@ std::string get_fallback(const proto::Message& message)
|
||||
}
|
||||
|
||||
}}}//end namespaces
|
||||
|
||||
@@ -63,14 +63,41 @@ ICEOptions {
|
||||
channel {
|
||||
name: "oil" #these names are arbitrary and are for debugging
|
||||
market_type: 5 #ICE Futures Brent, IPE Brent Futures
|
||||
market_type: 9 #ICE Futures WTI, ICE WTI Crude Futures
|
||||
uds_market_type: 5
|
||||
market_type: 9 #ICE Futures WTI, ICE WTI Crude Futures
|
||||
uds_market_type: 9
|
||||
##market_type: 13 #ICE Heating Oil Futures
|
||||
##uds_market_type: 13
|
||||
##market_type: 15 #ICE NYH (RBOB) Gasoline Futures
|
||||
##uds_market_type: 15
|
||||
##market_type: 21 #ICE Futures US Agricultures, Coffee C
|
||||
##uds_market_type: 21
|
||||
##market_type: 23 #ICE Futures US Agricultures, FCOJ A
|
||||
##uds_market_type: 23
|
||||
|
||||
market_type: 26 #ICE Futures US Financials DX
|
||||
uds_market_type: 26
|
||||
|
||||
uds_market_type: 11 #ICE WTI-Brent spreads
|
||||
##uds_market_type: 14 #ICE Heating Oil/WTI Futures Crack
|
||||
##uds_market_type: 16 #ICE NYH (RBOB) Gasoline/WTI Futures Crack
|
||||
##uds_market_type: 58 #ICE Futures UI Heating Oil / Brent
|
||||
##uds_market_type: 59 #ICE NYH (RBOB) Gasoline/Brent Futures Crack
|
||||
|
||||
# market_type: 44 #ICE Henry Hub
|
||||
# uds_market_type: 44
|
||||
|
||||
# market_type: 1 #ICE Financial Power
|
||||
# uds_market_type: 1
|
||||
#udp_buffer_size: 33554432 #32mb
|
||||
#onixs_log_mode: Debug
|
||||
}
|
||||
channel {
|
||||
name: "juice"
|
||||
market_type: 23 #ICE Futures US Agricultures, FCOJ A
|
||||
}
|
||||
# channel {
|
||||
# name: "juice"
|
||||
# market_type: 26 #ICE Futures US Agricultures, FCOJ A
|
||||
# }
|
||||
ice_config_file: "ConnectivityConfiguration.APITest.xml"
|
||||
#ice_config_file: "ConnectivityConfiguration.PerfTest.xml"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ Ports {
|
||||
value {
|
||||
config_port: 8000
|
||||
qbus_port: 8001
|
||||
exchange_sim_fix_port: 8002
|
||||
glbx_sim_fix_port: 8002
|
||||
ice_sim_fix_port: 8003
|
||||
replicator_port: 8080
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ SymbolList {
|
||||
symbol: "FOB"
|
||||
symbol: "GC"
|
||||
symbol: "GE"
|
||||
symbol: "GLI"
|
||||
symbol: "HE"
|
||||
symbol: "HG"
|
||||
symbol: "HO"
|
||||
@@ -66,9 +65,18 @@ SymbolLists
|
||||
list
|
||||
{
|
||||
key: "ICE"
|
||||
# symbol: "BRN"
|
||||
# symbol: "WBS"
|
||||
# symbol: "OJ"
|
||||
symbol: "BRN"
|
||||
symbol: "WBS"
|
||||
symbol: "OJ"
|
||||
symbol: "KC"
|
||||
symbol: "UHO"
|
||||
symbol: "UHU"
|
||||
symbol: "DX"
|
||||
|
||||
symbol: "HEN"
|
||||
symbol: "HIS"
|
||||
symbol: "HNG"
|
||||
symbol: "*"
|
||||
}
|
||||
list
|
||||
{
|
||||
@@ -112,5 +120,9 @@ Symbols {
|
||||
future: @SymbolLists.list[ICE].symbol
|
||||
spread: @SymbolLists.list[ICE].symbol
|
||||
}
|
||||
simice {
|
||||
future: @SymbolLists.list[ICE].symbol
|
||||
spread: @SymbolLists.list[ICE].symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
|
||||
AlgoPermissions {
|
||||
value {
|
||||
exchange_order_types: 'Market'
|
||||
exchange_order_types: 'Limit'
|
||||
exchange_order_types: 'Stop'
|
||||
exchange_order_types: 'StopLimit'
|
||||
exchange_order_types: 'GlbxIceberg'
|
||||
exchange_order_types: 'Iceberg'
|
||||
exchange_order_types: 'Lean'
|
||||
exchange_order_types: 'Join'
|
||||
exchange_order_types: 'Cover'
|
||||
exchange_order_types: 'Top'
|
||||
exchange_order_types: 'Offset'
|
||||
exchange_order_types: 'Splitter'
|
||||
exchange_order_types: 'Scratch'
|
||||
exchange_order_types: 'Prorata'
|
||||
exchange_order_types: 'Twap'
|
||||
|
||||
spreader_order_types: 'Spreader'
|
||||
spreader_order_types: 'Iceberg'
|
||||
spreader_order_types: 'Lean'
|
||||
spreader_order_types: 'Join'
|
||||
spreader_order_types: 'Cover'
|
||||
spreader_order_types: 'Top'
|
||||
spreader_order_types: 'Splitter'
|
||||
spreader_order_types: 'Scratch'
|
||||
spreader_order_types: 'Prorata'
|
||||
|
||||
attachable_order_types: 'Iceberg'
|
||||
attachable_order_types: 'Lean'
|
||||
attachable_order_types: 'Join'
|
||||
attachable_order_types: 'Cover'
|
||||
attachable_order_types: 'Top'
|
||||
attachable_order_types: 'Offset'
|
||||
attachable_order_types: 'Scratch'
|
||||
attachable_order_types: 'Prorata'
|
||||
attachable_order_types: 'Twap'
|
||||
|
||||
outright_order_types: 'Market'
|
||||
outright_order_types: 'Limit'
|
||||
outright_order_types: 'Stop'
|
||||
outright_order_types: 'StopLimit'
|
||||
outright_order_types: 'GlbxIceberg'
|
||||
}
|
||||
}
|
||||
@@ -90,8 +90,6 @@ CppConfig
|
||||
cpp_entry { key: "8D" value: 1000 }
|
||||
cpp_entry { key: "8W" value: 1000 }
|
||||
cpp_entry { key: "8XN" value: 2500 }
|
||||
cpp_entry { key: "8ZN" value: 2500 }
|
||||
cpp_entry { key: "9FN" value: 2500 }
|
||||
cpp_entry { key: "9Q" value: 1000 }
|
||||
cpp_entry { key: "A0D" value: 100 }
|
||||
cpp_entry { key: "A0F" value: 100 }
|
||||
@@ -163,6 +161,7 @@ CppConfig
|
||||
cpp_entry { key: "AAW" value: 42000 }
|
||||
cpp_entry { key: "AB3" value: 80 }
|
||||
cpp_entry { key: "AB7" value: 1000 }
|
||||
cpp_entry { key: "ABF" value: 100 }
|
||||
cpp_entry { key: "ABH" value: 42000 }
|
||||
cpp_entry { key: "ABI" value: 1000 }
|
||||
cpp_entry { key: "ABS" value: 1000 }
|
||||
@@ -170,6 +169,7 @@ CppConfig
|
||||
cpp_entry { key: "ABX" value: 1000 }
|
||||
cpp_entry { key: "ABY" value: 1000 }
|
||||
cpp_entry { key: "AC0" value: 42000 }
|
||||
cpp_entry { key: "ACB" value: 1000 }
|
||||
cpp_entry { key: "ACD" value: 200000 }
|
||||
cpp_entry { key: "ACM" value: 1000 }
|
||||
cpp_entry { key: "ACT" value: 1000 }
|
||||
@@ -183,7 +183,7 @@ CppConfig
|
||||
cpp_entry { key: "AE5" value: 1000 }
|
||||
cpp_entry { key: "AE8" value: 5 }
|
||||
cpp_entry { key: "AE9" value: 80 }
|
||||
cpp_entry { key: "AEJ" value: 960 }
|
||||
cpp_entry { key: "AEB" value: 1000 }
|
||||
cpp_entry { key: "AEP" value: 25 }
|
||||
cpp_entry { key: "AET" value: 1000 }
|
||||
cpp_entry { key: "AEZ" value: 42000 }
|
||||
@@ -222,7 +222,6 @@ CppConfig
|
||||
cpp_entry { key: "AJB" value: 1000 }
|
||||
cpp_entry { key: "AJJ" value: 5 }
|
||||
cpp_entry { key: "AJL" value: 42000 }
|
||||
cpp_entry { key: "AJP" value: 960 }
|
||||
cpp_entry { key: "AJR" value: 1000 }
|
||||
cpp_entry { key: "AJS" value: 42000 }
|
||||
cpp_entry { key: "AJU" value: 42000 }
|
||||
@@ -346,7 +345,6 @@ CppConfig
|
||||
cpp_entry { key: "BCF" value: 50 }
|
||||
cpp_entry { key: "BCH" value: 50 }
|
||||
cpp_entry { key: "BDB" value: 1000 }
|
||||
cpp_entry { key: "BDI" value: 100 }
|
||||
cpp_entry { key: "BDS" value: 1000 }
|
||||
cpp_entry { key: "BFR" value: 100 }
|
||||
cpp_entry { key: "BG" value: 1000 }
|
||||
@@ -357,13 +355,12 @@ CppConfig
|
||||
cpp_entry { key: "BOO" value: 6350 }
|
||||
cpp_entry { key: "BOS" value: 250 }
|
||||
cpp_entry { key: "BR7" value: 1000 }
|
||||
cpp_entry { key: "BSW" value: 136 }
|
||||
cpp_entry { key: "BSF" value: 25 }
|
||||
cpp_entry { key: "BTC" value: 5 }
|
||||
cpp_entry { key: "BTT" value: 50 }
|
||||
cpp_entry { key: "BUB" value: 1000 }
|
||||
cpp_entry { key: "BUC" value: 42000 }
|
||||
cpp_entry { key: "BUS" value: 20 }
|
||||
cpp_entry { key: "BUW" value: 20 }
|
||||
cpp_entry { key: "BWF" value: 50 }
|
||||
cpp_entry { key: "BWH" value: 50 }
|
||||
cpp_entry { key: "BZ" value: 1000 }
|
||||
@@ -394,6 +391,7 @@ CppConfig
|
||||
cpp_entry { key: "CFB" value: 1000 }
|
||||
cpp_entry { key: "CFC" value: 1000 }
|
||||
cpp_entry { key: "CGB" value: 42000 }
|
||||
cpp_entry { key: "CHB" value: 1000 }
|
||||
cpp_entry { key: "CHI" value: 250 }
|
||||
cpp_entry { key: "CHL" value: 100000 }
|
||||
cpp_entry { key: "CHP" value: 50000000 }
|
||||
@@ -406,9 +404,11 @@ CppConfig
|
||||
cpp_entry { key: "CL" value: 1000 }
|
||||
cpp_entry { key: "CL1" value: 1000 }
|
||||
cpp_entry { key: "CL2" value: 1000 }
|
||||
cpp_entry { key: "CLD" value: 1000 }
|
||||
cpp_entry { key: "CLL" value: 1000 }
|
||||
cpp_entry { key: "CLS" value: 1000 }
|
||||
cpp_entry { key: "CLT" value: 1000 }
|
||||
cpp_entry { key: "CMB" value: 1000 }
|
||||
cpp_entry { key: "CMF" value: 1000 }
|
||||
cpp_entry { key: "CNH" value: 100000 }
|
||||
cpp_entry { key: "COL" value: 80 }
|
||||
@@ -431,7 +431,6 @@ CppConfig
|
||||
cpp_entry { key: "CUS" value: 250 }
|
||||
cpp_entry { key: "CY" value: 1000 }
|
||||
cpp_entry { key: "CZK" value: 4000000 }
|
||||
cpp_entry { key: "CZN" value: 2500 }
|
||||
cpp_entry { key: "D0" value: 20 }
|
||||
cpp_entry { key: "D0X" value: 20 }
|
||||
cpp_entry { key: "D0Z" value: 20 }
|
||||
@@ -461,9 +460,9 @@ CppConfig
|
||||
cpp_entry { key: "DDO" value: 1000 }
|
||||
cpp_entry { key: "DEB" value: 744 }
|
||||
cpp_entry { key: "DEN" value: 250 }
|
||||
cpp_entry { key: "DEP" value: 252 }
|
||||
cpp_entry { key: "DEP" value: 264 }
|
||||
cpp_entry { key: "DFL" value: 100 }
|
||||
cpp_entry { key: "DFT" value: 100 }
|
||||
cpp_entry { key: "DFN" value: 100 }
|
||||
cpp_entry { key: "DG2" value: 100 }
|
||||
cpp_entry { key: "DG3" value: 100 }
|
||||
cpp_entry { key: "DGH" value: 1000 }
|
||||
@@ -472,7 +471,6 @@ CppConfig
|
||||
cpp_entry { key: "DGT" value: 100 }
|
||||
cpp_entry { key: "DHA" value: 80 }
|
||||
cpp_entry { key: "DHI" value: 1000 }
|
||||
cpp_entry { key: "DIH" value: 2500 }
|
||||
cpp_entry { key: "DJR" value: 100 }
|
||||
cpp_entry { key: "DKR" value: 1000 }
|
||||
cpp_entry { key: "DMB" value: 100 }
|
||||
@@ -503,7 +501,6 @@ CppConfig
|
||||
cpp_entry { key: "EAC" value: 80 }
|
||||
cpp_entry { key: "EAD" value: 125000 }
|
||||
cpp_entry { key: "EAE" value: 5 }
|
||||
cpp_entry { key: "EAF" value: 1000 }
|
||||
cpp_entry { key: "EAW" value: 80 }
|
||||
cpp_entry { key: "EBE" value: 1000 }
|
||||
cpp_entry { key: "ECD" value: 125000 }
|
||||
@@ -542,7 +539,6 @@ CppConfig
|
||||
cpp_entry { key: "EST" value: 50 }
|
||||
cpp_entry { key: "ETT" value: 100 }
|
||||
cpp_entry { key: "EUB" value: 80 }
|
||||
cpp_entry { key: "EUL" value: 1000 }
|
||||
cpp_entry { key: "EURADC" value: 1 }
|
||||
cpp_entry { key: "EURBPC" value: 1 }
|
||||
cpp_entry { key: "EURBPN" value: 1 }
|
||||
@@ -668,17 +664,24 @@ CppConfig
|
||||
cpp_entry { key: "H4X" value: 20 }
|
||||
cpp_entry { key: "H4Z" value: 20 }
|
||||
cpp_entry { key: "H5" value: 20 }
|
||||
cpp_entry { key: "H5B" value: 1000 }
|
||||
cpp_entry { key: "H5F" value: 1000 }
|
||||
cpp_entry { key: "H5G" value: 1000 }
|
||||
cpp_entry { key: "H5L" value: 80 }
|
||||
cpp_entry { key: "H5X" value: 20 }
|
||||
cpp_entry { key: "H5Z" value: 20 }
|
||||
cpp_entry { key: "HB" value: 2500 }
|
||||
cpp_entry { key: "HBC" value: 1000 }
|
||||
cpp_entry { key: "HBR" value: 1000 }
|
||||
cpp_entry { key: "HCL" value: 1000 }
|
||||
cpp_entry { key: "HDB" value: 1000 }
|
||||
cpp_entry { key: "HE" value: 400 }
|
||||
cpp_entry { key: "HET" value: 400 }
|
||||
cpp_entry { key: "HG" value: 25000 }
|
||||
cpp_entry { key: "HG0" value: 25000 }
|
||||
cpp_entry { key: "HGB" value: 1000 }
|
||||
cpp_entry { key: "HGF" value: 25000 }
|
||||
cpp_entry { key: "HGK" value: 25000 }
|
||||
cpp_entry { key: "HGS" value: 25000 }
|
||||
cpp_entry { key: "HGT" value: 25000 }
|
||||
cpp_entry { key: "HH" value: 10000 }
|
||||
@@ -703,11 +706,16 @@ CppConfig
|
||||
cpp_entry { key: "HQX" value: 20 }
|
||||
cpp_entry { key: "HQZ" value: 20 }
|
||||
cpp_entry { key: "HRC" value: 20 }
|
||||
cpp_entry { key: "HRP" value: 20 }
|
||||
cpp_entry { key: "HS" value: 20 }
|
||||
cpp_entry { key: "HSX" value: 20 }
|
||||
cpp_entry { key: "HSZ" value: 20 }
|
||||
cpp_entry { key: "HTA" value: 1000 }
|
||||
cpp_entry { key: "HTB" value: 1000 }
|
||||
cpp_entry { key: "HTC" value: 1000 }
|
||||
cpp_entry { key: "HTE" value: 1000 }
|
||||
cpp_entry { key: "HTI" value: 1000 }
|
||||
cpp_entry { key: "HTM" value: 1000 }
|
||||
cpp_entry { key: "HTT" value: 1000 }
|
||||
cpp_entry { key: "HUF" value: 30000000 }
|
||||
cpp_entry { key: "HWA" value: 80 }
|
||||
@@ -719,7 +727,6 @@ CppConfig
|
||||
cpp_entry { key: "ICI" value: 1000 }
|
||||
cpp_entry { key: "IDL" value: 5 }
|
||||
cpp_entry { key: "IH" value: 50 }
|
||||
cpp_entry { key: "ILB" value: 1750 }
|
||||
cpp_entry { key: "ILS" value: 1000000 }
|
||||
cpp_entry { key: "IN" value: 2500 }
|
||||
cpp_entry { key: "IP" value: 50 }
|
||||
@@ -727,11 +734,12 @@ CppConfig
|
||||
cpp_entry { key: "IPT" value: 10 }
|
||||
cpp_entry { key: "IS" value: 50 }
|
||||
cpp_entry { key: "ITB" value: 744 }
|
||||
cpp_entry { key: "ITP" value: 252 }
|
||||
cpp_entry { key: "ITP" value: 264 }
|
||||
cpp_entry { key: "IW" value: 50 }
|
||||
cpp_entry { key: "J4L" value: 80 }
|
||||
cpp_entry { key: "J7" value: 6250000 }
|
||||
cpp_entry { key: "JA" value: 1000 }
|
||||
cpp_entry { key: "JCC" value: 1000 }
|
||||
cpp_entry { key: "JDL" value: 80 }
|
||||
cpp_entry { key: "JE" value: 42000 }
|
||||
cpp_entry { key: "JET" value: 42000 }
|
||||
@@ -740,7 +748,7 @@ CppConfig
|
||||
cpp_entry { key: "JKB" value: 10000 }
|
||||
cpp_entry { key: "JKF" value: 10000 }
|
||||
cpp_entry { key: "JKM" value: 10000 }
|
||||
cpp_entry { key: "JML" value: 200 }
|
||||
cpp_entry { key: "JML" value: 480 }
|
||||
cpp_entry { key: "JNC" value: 1000 }
|
||||
cpp_entry { key: "JNG" value: 10000 }
|
||||
cpp_entry { key: "JNL" value: 80 }
|
||||
@@ -809,6 +817,9 @@ CppConfig
|
||||
cpp_entry { key: "LSW" value: 1000 }
|
||||
cpp_entry { key: "LT" value: 42000 }
|
||||
cpp_entry { key: "LWB" value: 1000 }
|
||||
cpp_entry { key: "M1B" value: 10 }
|
||||
cpp_entry { key: "M2K" value: 5 }
|
||||
cpp_entry { key: "M35" value: 10 }
|
||||
cpp_entry { key: "M5F" value: 10 }
|
||||
cpp_entry { key: "M6A" value: 10000 }
|
||||
cpp_entry { key: "M6B" value: 6250 }
|
||||
@@ -839,10 +850,11 @@ CppConfig
|
||||
cpp_entry { key: "MEB" value: 100 }
|
||||
cpp_entry { key: "MEE" value: 100 }
|
||||
cpp_entry { key: "MEF" value: 10 }
|
||||
cpp_entry { key: "MEL" value: 840 }
|
||||
cpp_entry { key: "MEO" value: 100 }
|
||||
cpp_entry { key: "MES" value: 5 }
|
||||
cpp_entry { key: "MEW" value: 100 }
|
||||
cpp_entry { key: "MFB" value: 1000 }
|
||||
cpp_entry { key: "MFC" value: 100 }
|
||||
cpp_entry { key: "MFD" value: 100 }
|
||||
cpp_entry { key: "MFF" value: 1000 }
|
||||
cpp_entry { key: "MFP" value: 100 }
|
||||
@@ -879,6 +891,7 @@ CppConfig
|
||||
cpp_entry { key: "MNE" value: 100 }
|
||||
cpp_entry { key: "MNG" value: 2500 }
|
||||
cpp_entry { key: "MNH" value: 10000 }
|
||||
cpp_entry { key: "MNQ" value: 2 }
|
||||
cpp_entry { key: "MNS" value: 635 }
|
||||
cpp_entry { key: "MNT" value: 80 }
|
||||
cpp_entry { key: "MO" value: 1000 }
|
||||
@@ -910,6 +923,7 @@ CppConfig
|
||||
cpp_entry { key: "MXB" value: 35000 }
|
||||
cpp_entry { key: "MXL" value: 5 }
|
||||
cpp_entry { key: "MXR" value: 35000 }
|
||||
cpp_entry { key: "MYM" value: 0.5 }
|
||||
cpp_entry { key: "N1B" value: 1000 }
|
||||
cpp_entry { key: "N1R" value: 10 }
|
||||
cpp_entry { key: "N1T" value: 10 }
|
||||
@@ -927,7 +941,6 @@ CppConfig
|
||||
cpp_entry { key: "NCF" value: 100 }
|
||||
cpp_entry { key: "NCO" value: 5 }
|
||||
cpp_entry { key: "NCP" value: 100 }
|
||||
cpp_entry { key: "NEN" value: 2500 }
|
||||
cpp_entry { key: "NEO" value: 5 }
|
||||
cpp_entry { key: "NEP" value: 80 }
|
||||
cpp_entry { key: "NFC" value: 1000 }
|
||||
@@ -941,10 +954,14 @@ CppConfig
|
||||
cpp_entry { key: "NHN" value: 2500 }
|
||||
cpp_entry { key: "NHO" value: 5 }
|
||||
cpp_entry { key: "NHP" value: 80 }
|
||||
cpp_entry { key: "NIM" value: 500 }
|
||||
cpp_entry { key: "NIT" value: 500 }
|
||||
cpp_entry { key: "NIY" value: 500 }
|
||||
cpp_entry { key: "NJ" value: 2500 }
|
||||
cpp_entry { key: "NKD" value: 5 }
|
||||
cpp_entry { key: "NKM" value: 5 }
|
||||
cpp_entry { key: "NKN" value: 2500 }
|
||||
cpp_entry { key: "NKT" value: 5 }
|
||||
cpp_entry { key: "NL" value: 2500 }
|
||||
cpp_entry { key: "NLS" value: 42000 }
|
||||
cpp_entry { key: "NMO" value: 5 }
|
||||
@@ -984,7 +1001,7 @@ CppConfig
|
||||
cpp_entry { key: "NYR" value: 42000 }
|
||||
cpp_entry { key: "NYT" value: 1000 }
|
||||
cpp_entry { key: "NZDUSC" value: 1 }
|
||||
cpp_entry { key: "NZN" value: 2500 }
|
||||
cpp_entry { key: "NZDUSD" value: 1 }
|
||||
cpp_entry { key: "OAD" value: 1 }
|
||||
cpp_entry { key: "ODO" value: 1000 }
|
||||
cpp_entry { key: "OFF" value: 5 }
|
||||
@@ -1000,6 +1017,7 @@ CppConfig
|
||||
cpp_entry { key: "OVL" value: 5 }
|
||||
cpp_entry { key: "PA" value: 100 }
|
||||
cpp_entry { key: "PAL" value: 80 }
|
||||
cpp_entry { key: "PAM" value: 10 }
|
||||
cpp_entry { key: "PAT" value: 100 }
|
||||
cpp_entry { key: "PBO" value: 5 }
|
||||
cpp_entry { key: "PBP" value: 80 }
|
||||
@@ -1020,7 +1038,6 @@ CppConfig
|
||||
cpp_entry { key: "PHF" value: 5 }
|
||||
cpp_entry { key: "PHO" value: 5 }
|
||||
cpp_entry { key: "PHP" value: 80 }
|
||||
cpp_entry { key: "PIO" value: 500 }
|
||||
cpp_entry { key: "PJY" value: 125000 }
|
||||
cpp_entry { key: "PKP" value: 80 }
|
||||
cpp_entry { key: "PL" value: 50 }
|
||||
@@ -1082,6 +1099,8 @@ CppConfig
|
||||
cpp_entry { key: "R2T" value: 10 }
|
||||
cpp_entry { key: "R2V" value: 50 }
|
||||
cpp_entry { key: "R53" value: 1000 }
|
||||
cpp_entry { key: "R5B" value: 1000 }
|
||||
cpp_entry { key: "R5E" value: 1000 }
|
||||
cpp_entry { key: "R5F" value: 1000 }
|
||||
cpp_entry { key: "R5M" value: 100 }
|
||||
cpp_entry { key: "R5O" value: 10 }
|
||||
@@ -1091,6 +1110,7 @@ CppConfig
|
||||
cpp_entry { key: "RBF" value: 100 }
|
||||
cpp_entry { key: "RBG" value: 42000 }
|
||||
cpp_entry { key: "RBL" value: 42000 }
|
||||
cpp_entry { key: "RBM" value: 100 }
|
||||
cpp_entry { key: "RBS" value: 42000 }
|
||||
cpp_entry { key: "RBT" value: 42000 }
|
||||
cpp_entry { key: "REX" value: 100 }
|
||||
@@ -1119,13 +1139,15 @@ CppConfig
|
||||
cpp_entry { key: "RYA" value: 42000 }
|
||||
cpp_entry { key: "S1U" value: 1000 }
|
||||
cpp_entry { key: "S53" value: 1000 }
|
||||
cpp_entry { key: "S5B" value: 1000 }
|
||||
cpp_entry { key: "S5F" value: 1000 }
|
||||
cpp_entry { key: "S5M" value: 100 }
|
||||
cpp_entry { key: "S5O" value: 10 }
|
||||
cpp_entry { key: "SBM" value: 100 }
|
||||
cpp_entry { key: "SBT" value: 50 }
|
||||
cpp_entry { key: "SD" value: 1000 }
|
||||
cpp_entry { key: "SDA" value: 250 }
|
||||
cpp_entry { key: "SDD" value: 1600 }
|
||||
cpp_entry { key: "SDD" value: 1760 }
|
||||
cpp_entry { key: "SDG" value: 250 }
|
||||
cpp_entry { key: "SDI" value: 1000 }
|
||||
cpp_entry { key: "SDM" value: 100 }
|
||||
@@ -1157,12 +1179,14 @@ CppConfig
|
||||
cpp_entry { key: "SMT" value: 100 }
|
||||
cpp_entry { key: "SMU" value: 1000 }
|
||||
cpp_entry { key: "SMW" value: 100 }
|
||||
cpp_entry { key: "SOM" value: 500 }
|
||||
cpp_entry { key: "SON" value: 2500 }
|
||||
cpp_entry { key: "SP" value: 250 }
|
||||
cpp_entry { key: "SR1" value: 4167 }
|
||||
cpp_entry { key: "SR3" value: 2500 }
|
||||
cpp_entry { key: "SR5" value: 1000 }
|
||||
cpp_entry { key: "SRT" value: 1600 }
|
||||
cpp_entry { key: "SRB" value: 1000 }
|
||||
cpp_entry { key: "SRT" value: 1760 }
|
||||
cpp_entry { key: "SSI" value: 1000 }
|
||||
cpp_entry { key: "SSP" value: 5000 }
|
||||
cpp_entry { key: "SSW" value: 1000 }
|
||||
@@ -1173,25 +1197,31 @@ CppConfig
|
||||
cpp_entry { key: "STY" value: 1000 }
|
||||
cpp_entry { key: "SU" value: 250 }
|
||||
cpp_entry { key: "SUT" value: 250 }
|
||||
cpp_entry { key: "T02" value: 800 }
|
||||
cpp_entry { key: "T03" value: 800 }
|
||||
cpp_entry { key: "T04" value: 800 }
|
||||
cpp_entry { key: "T06" value: 800 }
|
||||
cpp_entry { key: "T07" value: 800 }
|
||||
cpp_entry { key: "T08" value: 800 }
|
||||
cpp_entry { key: "T09" value: 800 }
|
||||
cpp_entry { key: "T12" value: 800 }
|
||||
cpp_entry { key: "T13" value: 800 }
|
||||
cpp_entry { key: "T14" value: 800 }
|
||||
cpp_entry { key: "T17" value: 800 }
|
||||
cpp_entry { key: "T18" value: 800 }
|
||||
cpp_entry { key: "T15" value: 800 }
|
||||
cpp_entry { key: "T16" value: 800 }
|
||||
cpp_entry { key: "T19" value: 800 }
|
||||
cpp_entry { key: "T1U" value: 1000 }
|
||||
cpp_entry { key: "T20" value: 800 }
|
||||
cpp_entry { key: "T21" value: 800 }
|
||||
cpp_entry { key: "T24" value: 800 }
|
||||
cpp_entry { key: "T22" value: 800 }
|
||||
cpp_entry { key: "T23" value: 800 }
|
||||
cpp_entry { key: "T26" value: 800 }
|
||||
cpp_entry { key: "T27" value: 800 }
|
||||
cpp_entry { key: "T28" value: 800 }
|
||||
cpp_entry { key: "T29" value: 800 }
|
||||
cpp_entry { key: "T2B" value: 1000 }
|
||||
cpp_entry { key: "T2D" value: 1000 }
|
||||
cpp_entry { key: "T2M" value: 100 }
|
||||
cpp_entry { key: "T31" value: 800 }
|
||||
cpp_entry { key: "T30" value: 800 }
|
||||
cpp_entry { key: "T3B" value: 1000 }
|
||||
cpp_entry { key: "T3L" value: 80 }
|
||||
cpp_entry { key: "T4B" value: 1000 }
|
||||
@@ -1207,6 +1237,7 @@ CppConfig
|
||||
cpp_entry { key: "TC" value: 2500 }
|
||||
cpp_entry { key: "TC6" value: 1000 }
|
||||
cpp_entry { key: "TC9" value: 1000 }
|
||||
cpp_entry { key: "TCS" value: 1000 }
|
||||
cpp_entry { key: "TD3" value: 1000 }
|
||||
cpp_entry { key: "TD8" value: 1000 }
|
||||
cpp_entry { key: "TEX" value: 1000 }
|
||||
@@ -1216,6 +1247,7 @@ CppConfig
|
||||
cpp_entry { key: "THB" value: 1000 }
|
||||
cpp_entry { key: "THD" value: 10000 }
|
||||
cpp_entry { key: "TIC" value: 500 }
|
||||
cpp_entry { key: "TIL" value: 1000 }
|
||||
cpp_entry { key: "TIO" value: 500 }
|
||||
cpp_entry { key: "TK" value: 1000 }
|
||||
cpp_entry { key: "TKB" value: 1000 }
|
||||
@@ -1252,7 +1284,6 @@ CppConfig
|
||||
cpp_entry { key: "TUT" value: 1000 }
|
||||
cpp_entry { key: "TUX" value: 1000 }
|
||||
cpp_entry { key: "TW" value: 1000 }
|
||||
cpp_entry { key: "TXN" value: 2500 }
|
||||
cpp_entry { key: "TYT" value: 1000 }
|
||||
cpp_entry { key: "TYX" value: 1000 }
|
||||
cpp_entry { key: "TZ6" value: 2500 }
|
||||
@@ -1262,10 +1293,12 @@ CppConfig
|
||||
cpp_entry { key: "UB" value: 1000 }
|
||||
cpp_entry { key: "UCM" value: 100 }
|
||||
cpp_entry { key: "UDL" value: 80 }
|
||||
cpp_entry { key: "UFB" value: 100 }
|
||||
cpp_entry { key: "UFE" value: 100 }
|
||||
cpp_entry { key: "UFG" value: 100 }
|
||||
cpp_entry { key: "UFN" value: 100 }
|
||||
cpp_entry { key: "UFU" value: 100 }
|
||||
cpp_entry { key: "UFZ" value: 100 }
|
||||
cpp_entry { key: "UFV" value: 100 }
|
||||
cpp_entry { key: "UGG" value: 42000 }
|
||||
cpp_entry { key: "UKG" value: 310 }
|
||||
cpp_entry { key: "ULB" value: 42000 }
|
||||
@@ -1276,10 +1309,12 @@ CppConfig
|
||||
cpp_entry { key: "UNB" value: 1000 }
|
||||
cpp_entry { key: "UNS" value: 1000 }
|
||||
cpp_entry { key: "UR" value: 1000 }
|
||||
cpp_entry { key: "USC" value: 1000 }
|
||||
cpp_entry { key: "USDBRL" value: 1 }
|
||||
cpp_entry { key: "USDCAC" value: 1 }
|
||||
cpp_entry { key: "USDCAD" value: 1 }
|
||||
cpp_entry { key: "USDCAN" value: 1 }
|
||||
cpp_entry { key: "USDCHF" value: 10 }
|
||||
cpp_entry { key: "USDCKC" value: 1 }
|
||||
cpp_entry { key: "USDCLP" value: 1 }
|
||||
cpp_entry { key: "USDCNY" value: 1 }
|
||||
@@ -1309,6 +1344,7 @@ CppConfig
|
||||
cpp_entry { key: "USDTLC" value: 1 }
|
||||
cpp_entry { key: "USDTWD" value: 1 }
|
||||
cpp_entry { key: "USDZRC" value: 1 }
|
||||
cpp_entry { key: "USE" value: 1000 }
|
||||
cpp_entry { key: "UV" value: 1000 }
|
||||
cpp_entry { key: "UX" value: 250 }
|
||||
cpp_entry { key: "V3L" value: 5 }
|
||||
@@ -1338,6 +1374,7 @@ CppConfig
|
||||
cpp_entry { key: "WTA" value: 1000 }
|
||||
cpp_entry { key: "WTD" value: 1000 }
|
||||
cpp_entry { key: "WTI" value: 1000 }
|
||||
cpp_entry { key: "WTL" value: 1000 }
|
||||
cpp_entry { key: "WTS" value: 1000 }
|
||||
cpp_entry { key: "WTT" value: 1000 }
|
||||
cpp_entry { key: "X0" value: 1000 }
|
||||
@@ -1390,6 +1427,7 @@ CppConfig
|
||||
cpp_entry { key: "YWE" value: 80 }
|
||||
cpp_entry { key: "YWF" value: 5 }
|
||||
cpp_entry { key: "YWK" value: 5 }
|
||||
cpp_entry { key: "Z00000" value: 1000 }
|
||||
cpp_entry { key: "Z1B" value: 100 }
|
||||
cpp_entry { key: "Z3N" value: 2000 }
|
||||
cpp_entry { key: "Z4" value: 1000 }
|
||||
@@ -1507,8 +1545,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "8D" value: NYMEX }
|
||||
cme_mic { key: "8W" value: NYMEX }
|
||||
cme_mic { key: "8XN" value: NYMEX }
|
||||
cme_mic { key: "8ZN" value: NYMEX }
|
||||
cme_mic { key: "9FN" value: NYMEX }
|
||||
cme_mic { key: "9Q" value: NYMEX }
|
||||
cme_mic { key: "A0D" value: NYMEX }
|
||||
cme_mic { key: "A0F" value: NYMEX }
|
||||
@@ -1580,6 +1616,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "AAW" value: NYMEX }
|
||||
cme_mic { key: "AB3" value: NYMEX }
|
||||
cme_mic { key: "AB7" value: NYMEX }
|
||||
cme_mic { key: "ABF" value: NYMEX }
|
||||
cme_mic { key: "ABH" value: NYMEX }
|
||||
cme_mic { key: "ABI" value: NYMEX }
|
||||
cme_mic { key: "ABS" value: NYMEX }
|
||||
@@ -1587,6 +1624,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "ABX" value: NYMEX }
|
||||
cme_mic { key: "ABY" value: NYMEX }
|
||||
cme_mic { key: "AC0" value: NYMEX }
|
||||
cme_mic { key: "ACB" value: NYMEX }
|
||||
cme_mic { key: "ACD" value: CME }
|
||||
cme_mic { key: "ACM" value: NYMEX }
|
||||
cme_mic { key: "ACT" value: NYMEX }
|
||||
@@ -1600,7 +1638,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "AE5" value: NYMEX }
|
||||
cme_mic { key: "AE8" value: NYMEX }
|
||||
cme_mic { key: "AE9" value: NYMEX }
|
||||
cme_mic { key: "AEJ" value: NYMEX }
|
||||
cme_mic { key: "AEB" value: NYMEX }
|
||||
cme_mic { key: "AEP" value: COMEX }
|
||||
cme_mic { key: "AET" value: NYMEX }
|
||||
cme_mic { key: "AEZ" value: NYMEX }
|
||||
@@ -1639,7 +1677,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "AJB" value: NYMEX }
|
||||
cme_mic { key: "AJJ" value: NYMEX }
|
||||
cme_mic { key: "AJL" value: NYMEX }
|
||||
cme_mic { key: "AJP" value: NYMEX }
|
||||
cme_mic { key: "AJR" value: NYMEX }
|
||||
cme_mic { key: "AJS" value: NYMEX }
|
||||
cme_mic { key: "AJU" value: NYMEX }
|
||||
@@ -1763,7 +1800,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "BCF" value: CBT }
|
||||
cme_mic { key: "BCH" value: CBT }
|
||||
cme_mic { key: "BDB" value: NYMEX }
|
||||
cme_mic { key: "BDI" value: CME }
|
||||
cme_mic { key: "BDS" value: DME }
|
||||
cme_mic { key: "BFR" value: NYMEX }
|
||||
cme_mic { key: "BG" value: NYMEX }
|
||||
@@ -1774,13 +1810,12 @@ CmeSymbolMics
|
||||
cme_mic { key: "BOO" value: NYMEX }
|
||||
cme_mic { key: "BOS" value: CME }
|
||||
cme_mic { key: "BR7" value: NYMEX }
|
||||
cme_mic { key: "BSW" value: CBT }
|
||||
cme_mic { key: "BSF" value: CBT }
|
||||
cme_mic { key: "BTC" value: CME }
|
||||
cme_mic { key: "BTT" value: CME }
|
||||
cme_mic { key: "BUB" value: CBT }
|
||||
cme_mic { key: "BUC" value: NYMEX }
|
||||
cme_mic { key: "BUS" value: NYMEX }
|
||||
cme_mic { key: "BUW" value: NYMSW }
|
||||
cme_mic { key: "BWF" value: CBT }
|
||||
cme_mic { key: "BWH" value: CBT }
|
||||
cme_mic { key: "BZ" value: NYMEX }
|
||||
@@ -1811,6 +1846,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "CFB" value: NYMEX }
|
||||
cme_mic { key: "CFC" value: NYMEX }
|
||||
cme_mic { key: "CGB" value: NYMEX }
|
||||
cme_mic { key: "CHB" value: NYMEX }
|
||||
cme_mic { key: "CHI" value: CME }
|
||||
cme_mic { key: "CHL" value: CME }
|
||||
cme_mic { key: "CHP" value: CME }
|
||||
@@ -1823,9 +1859,11 @@ CmeSymbolMics
|
||||
cme_mic { key: "CL" value: NYMEX }
|
||||
cme_mic { key: "CL1" value: NYMEX }
|
||||
cme_mic { key: "CL2" value: NYMEX }
|
||||
cme_mic { key: "CLD" value: NYMEX }
|
||||
cme_mic { key: "CLL" value: NYMEX }
|
||||
cme_mic { key: "CLS" value: NYMEX }
|
||||
cme_mic { key: "CLT" value: NYMEX }
|
||||
cme_mic { key: "CMB" value: NYMEX }
|
||||
cme_mic { key: "CMF" value: NYMEX }
|
||||
cme_mic { key: "CNH" value: CME }
|
||||
cme_mic { key: "COL" value: NYMEX }
|
||||
@@ -1848,7 +1886,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "CUS" value: CME }
|
||||
cme_mic { key: "CY" value: NYMEX }
|
||||
cme_mic { key: "CZK" value: CME }
|
||||
cme_mic { key: "CZN" value: NYMEX }
|
||||
cme_mic { key: "D0" value: CME }
|
||||
cme_mic { key: "D0X" value: CME }
|
||||
cme_mic { key: "D0Z" value: CME }
|
||||
@@ -1880,7 +1917,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "DEN" value: CME }
|
||||
cme_mic { key: "DEP" value: NYMEX }
|
||||
cme_mic { key: "DFL" value: CBT }
|
||||
cme_mic { key: "DFT" value: CBT }
|
||||
cme_mic { key: "DFN" value: CBT }
|
||||
cme_mic { key: "DG2" value: CBT }
|
||||
cme_mic { key: "DG3" value: CBT }
|
||||
cme_mic { key: "DGH" value: DME }
|
||||
@@ -1889,7 +1926,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "DGT" value: CBT }
|
||||
cme_mic { key: "DHA" value: NYMEX }
|
||||
cme_mic { key: "DHI" value: DME }
|
||||
cme_mic { key: "DIH" value: NYMEX }
|
||||
cme_mic { key: "DJR" value: CBT }
|
||||
cme_mic { key: "DKR" value: DME }
|
||||
cme_mic { key: "DMB" value: DME }
|
||||
@@ -1920,7 +1956,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "EAC" value: NYMEX }
|
||||
cme_mic { key: "EAD" value: CME }
|
||||
cme_mic { key: "EAE" value: NYMEX }
|
||||
cme_mic { key: "EAF" value: NYMEX }
|
||||
cme_mic { key: "EAW" value: NYMEX }
|
||||
cme_mic { key: "EBE" value: NYMEX }
|
||||
cme_mic { key: "ECD" value: CME }
|
||||
@@ -1959,7 +1994,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "EST" value: CME }
|
||||
cme_mic { key: "ETT" value: CME }
|
||||
cme_mic { key: "EUB" value: NYMEX }
|
||||
cme_mic { key: "EUL" value: NYMEX }
|
||||
cme_mic { key: "EURADC" value: CME }
|
||||
cme_mic { key: "EURBPC" value: CME }
|
||||
cme_mic { key: "EURBPN" value: CME }
|
||||
@@ -2085,17 +2119,24 @@ CmeSymbolMics
|
||||
cme_mic { key: "H4X" value: CME }
|
||||
cme_mic { key: "H4Z" value: CME }
|
||||
cme_mic { key: "H5" value: CME }
|
||||
cme_mic { key: "H5B" value: NYMEX }
|
||||
cme_mic { key: "H5F" value: NYMEX }
|
||||
cme_mic { key: "H5G" value: NYMEX }
|
||||
cme_mic { key: "H5L" value: NYMEX }
|
||||
cme_mic { key: "H5X" value: CME }
|
||||
cme_mic { key: "H5Z" value: CME }
|
||||
cme_mic { key: "HB" value: NYMEX }
|
||||
cme_mic { key: "HBC" value: NYMEX }
|
||||
cme_mic { key: "HBR" value: NYMEX }
|
||||
cme_mic { key: "HCL" value: NYMEX }
|
||||
cme_mic { key: "HDB" value: NYMEX }
|
||||
cme_mic { key: "HE" value: CME }
|
||||
cme_mic { key: "HET" value: CME }
|
||||
cme_mic { key: "HG" value: COMEX }
|
||||
cme_mic { key: "HG0" value: COMEX }
|
||||
cme_mic { key: "HGB" value: NYMEX }
|
||||
cme_mic { key: "HGF" value: COMEX }
|
||||
cme_mic { key: "HGK" value: COMEX }
|
||||
cme_mic { key: "HGS" value: COMEX }
|
||||
cme_mic { key: "HGT" value: COMEX }
|
||||
cme_mic { key: "HH" value: NYMEX }
|
||||
@@ -2120,11 +2161,16 @@ CmeSymbolMics
|
||||
cme_mic { key: "HQX" value: CME }
|
||||
cme_mic { key: "HQZ" value: CME }
|
||||
cme_mic { key: "HRC" value: NYMEX }
|
||||
cme_mic { key: "HRP" value: COMEX }
|
||||
cme_mic { key: "HS" value: CME }
|
||||
cme_mic { key: "HSX" value: CME }
|
||||
cme_mic { key: "HSZ" value: CME }
|
||||
cme_mic { key: "HTA" value: NYMEX }
|
||||
cme_mic { key: "HTB" value: NYMEX }
|
||||
cme_mic { key: "HTC" value: NYMEX }
|
||||
cme_mic { key: "HTE" value: NYMEX }
|
||||
cme_mic { key: "HTI" value: NYMEX }
|
||||
cme_mic { key: "HTM" value: NYMEX }
|
||||
cme_mic { key: "HTT" value: NYMEX }
|
||||
cme_mic { key: "HUF" value: CME }
|
||||
cme_mic { key: "HWA" value: NYMEX }
|
||||
@@ -2136,7 +2182,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "ICI" value: NYMEX }
|
||||
cme_mic { key: "IDL" value: NYMEX }
|
||||
cme_mic { key: "IH" value: MGE }
|
||||
cme_mic { key: "ILB" value: NYMEX }
|
||||
cme_mic { key: "ILS" value: CME }
|
||||
cme_mic { key: "IN" value: NYMEX }
|
||||
cme_mic { key: "IP" value: MGE }
|
||||
@@ -2149,6 +2194,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "J4L" value: NYMEX }
|
||||
cme_mic { key: "J7" value: CME }
|
||||
cme_mic { key: "JA" value: NYMEX }
|
||||
cme_mic { key: "JCC" value: NYMEX }
|
||||
cme_mic { key: "JDL" value: NYMEX }
|
||||
cme_mic { key: "JE" value: NYMEX }
|
||||
cme_mic { key: "JET" value: NYMEX }
|
||||
@@ -2226,6 +2272,9 @@ CmeSymbolMics
|
||||
cme_mic { key: "LSW" value: NYMEX }
|
||||
cme_mic { key: "LT" value: NYMEX }
|
||||
cme_mic { key: "LWB" value: NYMEX }
|
||||
cme_mic { key: "M1B" value: NYMEX }
|
||||
cme_mic { key: "M2K" value: CME }
|
||||
cme_mic { key: "M35" value: NYMEX }
|
||||
cme_mic { key: "M5F" value: NYMEX }
|
||||
cme_mic { key: "M6A" value: CME }
|
||||
cme_mic { key: "M6B" value: CME }
|
||||
@@ -2256,10 +2305,11 @@ CmeSymbolMics
|
||||
cme_mic { key: "MEB" value: NYMEX }
|
||||
cme_mic { key: "MEE" value: NYMEX }
|
||||
cme_mic { key: "MEF" value: NYMEX }
|
||||
cme_mic { key: "MEL" value: NYMEX }
|
||||
cme_mic { key: "MEO" value: NYMEX }
|
||||
cme_mic { key: "MES" value: CME }
|
||||
cme_mic { key: "MEW" value: NYMEX }
|
||||
cme_mic { key: "MFB" value: NYMEX }
|
||||
cme_mic { key: "MFC" value: CBT }
|
||||
cme_mic { key: "MFD" value: NYMEX }
|
||||
cme_mic { key: "MFF" value: NYMEX }
|
||||
cme_mic { key: "MFP" value: NYMEX }
|
||||
@@ -2296,6 +2346,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "MNE" value: NYMEX }
|
||||
cme_mic { key: "MNG" value: NYMEX }
|
||||
cme_mic { key: "MNH" value: CME }
|
||||
cme_mic { key: "MNQ" value: CME }
|
||||
cme_mic { key: "MNS" value: NYMEX }
|
||||
cme_mic { key: "MNT" value: NYMEX }
|
||||
cme_mic { key: "MO" value: NYMEX }
|
||||
@@ -2327,6 +2378,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "MXB" value: NYMEX }
|
||||
cme_mic { key: "MXL" value: NYMEX }
|
||||
cme_mic { key: "MXR" value: NYMEX }
|
||||
cme_mic { key: "MYM" value: CBT }
|
||||
cme_mic { key: "N1B" value: NYMEX }
|
||||
cme_mic { key: "N1R" value: CME }
|
||||
cme_mic { key: "N1T" value: CME }
|
||||
@@ -2344,7 +2396,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "NCF" value: NYMEX }
|
||||
cme_mic { key: "NCO" value: NYMEX }
|
||||
cme_mic { key: "NCP" value: NYMEX }
|
||||
cme_mic { key: "NEN" value: NYMEX }
|
||||
cme_mic { key: "NEO" value: NYMEX }
|
||||
cme_mic { key: "NEP" value: NYMEX }
|
||||
cme_mic { key: "NFC" value: NYMEX }
|
||||
@@ -2358,10 +2409,14 @@ CmeSymbolMics
|
||||
cme_mic { key: "NHN" value: NYMEX }
|
||||
cme_mic { key: "NHO" value: NYMEX }
|
||||
cme_mic { key: "NHP" value: NYMEX }
|
||||
cme_mic { key: "NIM" value: CME }
|
||||
cme_mic { key: "NIT" value: CME }
|
||||
cme_mic { key: "NIY" value: CME }
|
||||
cme_mic { key: "NJ" value: NYMEX }
|
||||
cme_mic { key: "NKD" value: CME }
|
||||
cme_mic { key: "NKM" value: CME }
|
||||
cme_mic { key: "NKN" value: NYMEX }
|
||||
cme_mic { key: "NKT" value: CME }
|
||||
cme_mic { key: "NL" value: NYMEX }
|
||||
cme_mic { key: "NLS" value: NYMEX }
|
||||
cme_mic { key: "NMO" value: NYMEX }
|
||||
@@ -2401,7 +2456,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "NYR" value: NYMEX }
|
||||
cme_mic { key: "NYT" value: NYMEX }
|
||||
cme_mic { key: "NZDUSC" value: CME }
|
||||
cme_mic { key: "NZN" value: NYMEX }
|
||||
cme_mic { key: "NZDUSD" value: FXS }
|
||||
cme_mic { key: "OAD" value: NYMEX }
|
||||
cme_mic { key: "ODO" value: DME }
|
||||
cme_mic { key: "OFF" value: NYMEX }
|
||||
@@ -2417,6 +2472,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "OVL" value: NYMEX }
|
||||
cme_mic { key: "PA" value: NYMEX }
|
||||
cme_mic { key: "PAL" value: NYMEX }
|
||||
cme_mic { key: "PAM" value: NYMEX }
|
||||
cme_mic { key: "PAT" value: NYMEX }
|
||||
cme_mic { key: "PBO" value: NYMEX }
|
||||
cme_mic { key: "PBP" value: NYMEX }
|
||||
@@ -2437,7 +2493,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "PHF" value: NYMEX }
|
||||
cme_mic { key: "PHO" value: NYMEX }
|
||||
cme_mic { key: "PHP" value: NYMEX }
|
||||
cme_mic { key: "PIO" value: NYMEX }
|
||||
cme_mic { key: "PJY" value: CME }
|
||||
cme_mic { key: "PKP" value: NYMEX }
|
||||
cme_mic { key: "PL" value: NYMEX }
|
||||
@@ -2499,6 +2554,8 @@ CmeSymbolMics
|
||||
cme_mic { key: "R2T" value: CME }
|
||||
cme_mic { key: "R2V" value: CME }
|
||||
cme_mic { key: "R53" value: NYMEX }
|
||||
cme_mic { key: "R5B" value: NYMEX }
|
||||
cme_mic { key: "R5E" value: NYMEX }
|
||||
cme_mic { key: "R5F" value: NYMEX }
|
||||
cme_mic { key: "R5M" value: NYMEX }
|
||||
cme_mic { key: "R5O" value: NYMEX }
|
||||
@@ -2508,6 +2565,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "RBF" value: NYMEX }
|
||||
cme_mic { key: "RBG" value: NYMEX }
|
||||
cme_mic { key: "RBL" value: NYMEX }
|
||||
cme_mic { key: "RBM" value: NYMEX }
|
||||
cme_mic { key: "RBS" value: NYMEX }
|
||||
cme_mic { key: "RBT" value: NYMEX }
|
||||
cme_mic { key: "REX" value: CBT }
|
||||
@@ -2536,9 +2594,11 @@ CmeSymbolMics
|
||||
cme_mic { key: "RYA" value: NYMEX }
|
||||
cme_mic { key: "S1U" value: CBT }
|
||||
cme_mic { key: "S53" value: NYMEX }
|
||||
cme_mic { key: "S5B" value: NYMEX }
|
||||
cme_mic { key: "S5F" value: NYMEX }
|
||||
cme_mic { key: "S5M" value: NYMEX }
|
||||
cme_mic { key: "S5O" value: NYMEX }
|
||||
cme_mic { key: "SBM" value: NYMEX }
|
||||
cme_mic { key: "SBT" value: CBT }
|
||||
cme_mic { key: "SD" value: NYMEX }
|
||||
cme_mic { key: "SDA" value: CME }
|
||||
@@ -2574,11 +2634,13 @@ CmeSymbolMics
|
||||
cme_mic { key: "SMT" value: CME }
|
||||
cme_mic { key: "SMU" value: NYMEX }
|
||||
cme_mic { key: "SMW" value: NYMEX }
|
||||
cme_mic { key: "SOM" value: CBT }
|
||||
cme_mic { key: "SON" value: CME }
|
||||
cme_mic { key: "SP" value: CME }
|
||||
cme_mic { key: "SR1" value: CME }
|
||||
cme_mic { key: "SR3" value: CME }
|
||||
cme_mic { key: "SR5" value: NYMEX }
|
||||
cme_mic { key: "SRB" value: NYMEX }
|
||||
cme_mic { key: "SRT" value: NYMEX }
|
||||
cme_mic { key: "SSI" value: NYMEX }
|
||||
cme_mic { key: "SSP" value: COMEX }
|
||||
@@ -2590,25 +2652,31 @@ CmeSymbolMics
|
||||
cme_mic { key: "STY" value: NYMEX }
|
||||
cme_mic { key: "SU" value: CME }
|
||||
cme_mic { key: "SUT" value: CME }
|
||||
cme_mic { key: "T02" value: NYMEX }
|
||||
cme_mic { key: "T03" value: NYMEX }
|
||||
cme_mic { key: "T04" value: NYMEX }
|
||||
cme_mic { key: "T06" value: NYMEX }
|
||||
cme_mic { key: "T07" value: NYMEX }
|
||||
cme_mic { key: "T08" value: NYMEX }
|
||||
cme_mic { key: "T09" value: NYMEX }
|
||||
cme_mic { key: "T12" value: NYMEX }
|
||||
cme_mic { key: "T13" value: NYMEX }
|
||||
cme_mic { key: "T14" value: NYMEX }
|
||||
cme_mic { key: "T17" value: NYMEX }
|
||||
cme_mic { key: "T18" value: NYMEX }
|
||||
cme_mic { key: "T15" value: NYMEX }
|
||||
cme_mic { key: "T16" value: NYMEX }
|
||||
cme_mic { key: "T19" value: NYMEX }
|
||||
cme_mic { key: "T1U" value: CBT }
|
||||
cme_mic { key: "T20" value: NYMEX }
|
||||
cme_mic { key: "T21" value: NYMEX }
|
||||
cme_mic { key: "T24" value: NYMEX }
|
||||
cme_mic { key: "T22" value: NYMEX }
|
||||
cme_mic { key: "T23" value: NYMEX }
|
||||
cme_mic { key: "T26" value: NYMEX }
|
||||
cme_mic { key: "T27" value: NYMEX }
|
||||
cme_mic { key: "T28" value: NYMEX }
|
||||
cme_mic { key: "T29" value: NYMEX }
|
||||
cme_mic { key: "T2B" value: NYMEX }
|
||||
cme_mic { key: "T2D" value: NYMEX }
|
||||
cme_mic { key: "T2M" value: NYMEX }
|
||||
cme_mic { key: "T31" value: NYMEX }
|
||||
cme_mic { key: "T30" value: NYMEX }
|
||||
cme_mic { key: "T3B" value: NYMEX }
|
||||
cme_mic { key: "T3L" value: NYMEX }
|
||||
cme_mic { key: "T4B" value: NYMEX }
|
||||
@@ -2624,6 +2692,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "TC" value: NYMEX }
|
||||
cme_mic { key: "TC6" value: NYMEX }
|
||||
cme_mic { key: "TC9" value: NYMEX }
|
||||
cme_mic { key: "TCS" value: NYMEX }
|
||||
cme_mic { key: "TD3" value: NYMEX }
|
||||
cme_mic { key: "TD8" value: NYMEX }
|
||||
cme_mic { key: "TEX" value: CBT }
|
||||
@@ -2633,6 +2702,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "THB" value: NYMEX }
|
||||
cme_mic { key: "THD" value: NYMEX }
|
||||
cme_mic { key: "TIC" value: NYMEX }
|
||||
cme_mic { key: "TIL" value: NYMEX }
|
||||
cme_mic { key: "TIO" value: NYMEX }
|
||||
cme_mic { key: "TK" value: NYMEX }
|
||||
cme_mic { key: "TKB" value: NYMEX }
|
||||
@@ -2669,7 +2739,6 @@ CmeSymbolMics
|
||||
cme_mic { key: "TUT" value: CBT }
|
||||
cme_mic { key: "TUX" value: CBT }
|
||||
cme_mic { key: "TW" value: NYMEX }
|
||||
cme_mic { key: "TXN" value: NYMEX }
|
||||
cme_mic { key: "TYT" value: CBT }
|
||||
cme_mic { key: "TYX" value: CBT }
|
||||
cme_mic { key: "TZ6" value: NYMEX }
|
||||
@@ -2679,10 +2748,12 @@ CmeSymbolMics
|
||||
cme_mic { key: "UB" value: CBT }
|
||||
cme_mic { key: "UCM" value: NYMEX }
|
||||
cme_mic { key: "UDL" value: NYMEX }
|
||||
cme_mic { key: "UFB" value: CBT }
|
||||
cme_mic { key: "UFE" value: CBT }
|
||||
cme_mic { key: "UFG" value: CBT }
|
||||
cme_mic { key: "UFN" value: CBT }
|
||||
cme_mic { key: "UFU" value: CBT }
|
||||
cme_mic { key: "UFZ" value: CBT }
|
||||
cme_mic { key: "UFV" value: CBT }
|
||||
cme_mic { key: "UGG" value: NYMEX }
|
||||
cme_mic { key: "UKG" value: NYMEX }
|
||||
cme_mic { key: "ULB" value: NYMEX }
|
||||
@@ -2693,10 +2764,12 @@ CmeSymbolMics
|
||||
cme_mic { key: "UNB" value: NYMEX }
|
||||
cme_mic { key: "UNS" value: NYMEX }
|
||||
cme_mic { key: "UR" value: NYMEX }
|
||||
cme_mic { key: "USC" value: NYMEX }
|
||||
cme_mic { key: "USDBRL" value: CME }
|
||||
cme_mic { key: "USDCAC" value: CME }
|
||||
cme_mic { key: "USDCAD" value: FXS }
|
||||
cme_mic { key: "USDCAN" value: CME }
|
||||
cme_mic { key: "USDCHF" value: FXS }
|
||||
cme_mic { key: "USDCKC" value: CME }
|
||||
cme_mic { key: "USDCLP" value: CME }
|
||||
cme_mic { key: "USDCNY" value: CME }
|
||||
@@ -2726,6 +2799,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "USDTLC" value: CME }
|
||||
cme_mic { key: "USDTWD" value: CME }
|
||||
cme_mic { key: "USDZRC" value: CME }
|
||||
cme_mic { key: "USE" value: NYMEX }
|
||||
cme_mic { key: "UV" value: NYMEX }
|
||||
cme_mic { key: "UX" value: NYMEX }
|
||||
cme_mic { key: "V3L" value: NYMEX }
|
||||
@@ -2755,6 +2829,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "WTA" value: NYMEX }
|
||||
cme_mic { key: "WTD" value: NYMEX }
|
||||
cme_mic { key: "WTI" value: NYMEX }
|
||||
cme_mic { key: "WTL" value: NYMEX }
|
||||
cme_mic { key: "WTS" value: NYMEX }
|
||||
cme_mic { key: "WTT" value: NYMEX }
|
||||
cme_mic { key: "X0" value: NYMEX }
|
||||
@@ -2807,6 +2882,7 @@ CmeSymbolMics
|
||||
cme_mic { key: "YWE" value: NYMEX }
|
||||
cme_mic { key: "YWF" value: NYMEX }
|
||||
cme_mic { key: "YWK" value: NYMEX }
|
||||
cme_mic { key: "Z00000" value: CME }
|
||||
cme_mic { key: "Z1B" value: NYMEX }
|
||||
cme_mic { key: "Z3N" value: CBT }
|
||||
cme_mic { key: "Z4" value: NYMEX }
|
||||
|
||||
+352
-188
@@ -5,7 +5,7 @@ JetFIXSimConnection {
|
||||
name: "sim"
|
||||
platform: SIM
|
||||
socket_connect_host_ip: "127.0.0.1"
|
||||
socket_connect_port: @Ports.exchange_sim_fix_port
|
||||
socket_connect_port: @Ports.glbx_sim_fix_port
|
||||
sender_compid: "SPARK" # this is the FIX session name
|
||||
sender_subid: "BTS"
|
||||
target_compid: "BTS"
|
||||
@@ -18,9 +18,173 @@ JetFIXSimConnection {
|
||||
seconds_to_pause : 1
|
||||
max_connection_attempts: 9999999
|
||||
}
|
||||
sim_ice {
|
||||
name: "sim_ice"
|
||||
platform: SIMICE
|
||||
socket_connect_host_ip: "127.0.0.1"
|
||||
socket_connect_port: @Ports.ice_sim_fix_port
|
||||
sender_compid: "51239" # this is the FIX session name
|
||||
sender_subid: "BTS"
|
||||
target_compid: "BTS"
|
||||
target_subid: "BTS"
|
||||
cme_market_segment_id: 0
|
||||
end_time: "02:00:00"
|
||||
start_time: "02:05:00"
|
||||
raw_data: "1JE9X"
|
||||
use_cme_secure_logon: false
|
||||
seconds_to_pause : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JetFIX {
|
||||
rule: "CannedCertSession.name='ice_cert'"
|
||||
value {
|
||||
#connection: @JetFIXSimConnection.sim_ice
|
||||
connection {
|
||||
name: "ice_cert"
|
||||
platform: ICE
|
||||
use_cme_secure_logon: false
|
||||
log_fix_stream: true
|
||||
socket_connect_host_ip: "63.247.113.154"
|
||||
socket_connect_port: 80
|
||||
sender_compid: "51251"
|
||||
target_compid: "ICE"
|
||||
start_time: "22:55:00"
|
||||
end_time: "22:05:00"
|
||||
sender_subid: "BTS"
|
||||
user_name: "bluetrd-os" #this is the order_server_id
|
||||
raw_data: "Starts123"
|
||||
max_order_msgs_per_window: 300
|
||||
auto_fix_seq_num: true
|
||||
|
||||
seconds_to_replay: 6000
|
||||
}
|
||||
connection: @JetFIXSimConnection.sim
|
||||
#connection: @JetFIXSimConnection.sim_ice
|
||||
|
||||
connection {
|
||||
name: "cme_mc5_99"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.199"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "99"
|
||||
cme_market_segment_id: 99
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_58"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.172"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "58"
|
||||
cme_market_segment_id: 58
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_54"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.191"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "54"
|
||||
cme_market_segment_id: 54
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_82"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.179"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "82"
|
||||
cme_market_segment_id: 82
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_56"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.174"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "56"
|
||||
cme_market_segment_id: 56
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_50"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.202"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "50"
|
||||
cme_market_segment_id: 50
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_52"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.181"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "52"
|
||||
cme_market_segment_id: 52
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JetFIX {
|
||||
rule: "CannedCertSession.name='mc7'"
|
||||
value {
|
||||
@@ -456,193 +620,193 @@ JetFIX {
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_60"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.195"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "60"
|
||||
cme_market_segment_id: 60
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_76"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.204"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "76"
|
||||
cme_market_segment_id: 76
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_88"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.169"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "88"
|
||||
cme_market_segment_id: 88
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_74"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.197"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "74"
|
||||
cme_market_segment_id: 74
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_64"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.177"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "64"
|
||||
cme_market_segment_id: 64
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_72"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.189"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "72"
|
||||
cme_market_segment_id: 72
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_70"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.183"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "70"
|
||||
cme_market_segment_id: 70
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_68"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.168"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "68"
|
||||
cme_market_segment_id: 68
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_80"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.187"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "80"
|
||||
cme_market_segment_id: 80
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_84"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.198"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "84"
|
||||
cme_market_segment_id: 84
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
connection {
|
||||
name: "cme_mc5_78"
|
||||
platform: GLBX
|
||||
socket_connect_host_ip: "69.50.112.167"
|
||||
socket_connect_port: 61922
|
||||
sender_compid: "MC5004N"
|
||||
target_compid: "CME"
|
||||
target_subid: "78"
|
||||
cme_market_segment_id: 78
|
||||
start_time: "00:30:00"
|
||||
end_time: "23:30:00"
|
||||
start_day: "sunday"
|
||||
end_day: "friday"
|
||||
sender_subid: "BTS"
|
||||
raw_data: "S4PMA"
|
||||
auto_fix_seq_num: true
|
||||
}
|
||||
# connection {
|
||||
# name: "cme_mc5_60"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.195"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "60"
|
||||
# cme_market_segment_id: 60
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
# connection {
|
||||
# name: "cme_mc5_76"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.204"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "76"
|
||||
# cme_market_segment_id: 76
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
# connection {
|
||||
# name: "cme_mc5_88"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.169"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "88"
|
||||
# cme_market_segment_id: 88
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
# connection {
|
||||
# name: "cme_mc5_74"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.197"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "74"
|
||||
# cme_market_segment_id: 74
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
# connection {
|
||||
# name: "cme_mc5_64"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.177"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "64"
|
||||
# cme_market_segment_id: 64
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
# connection {
|
||||
# name: "cme_mc5_72"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.189"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "72"
|
||||
# cme_market_segment_id: 72
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
# connection {
|
||||
# name: "cme_mc5_70"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.183"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "70"
|
||||
# cme_market_segment_id: 70
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
# connection {
|
||||
# name: "cme_mc5_68"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.168"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "68"
|
||||
# cme_market_segment_id: 68
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
# connection {
|
||||
# name: "cme_mc5_80"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.187"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "80"
|
||||
# cme_market_segment_id: 80
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
# connection {
|
||||
# name: "cme_mc5_84"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.198"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "84"
|
||||
# cme_market_segment_id: 84
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
# connection {
|
||||
# name: "cme_mc5_78"
|
||||
# platform: GLBX
|
||||
# socket_connect_host_ip: "69.50.112.167"
|
||||
# socket_connect_port: 61922
|
||||
# sender_compid: "MC5004N"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "78"
|
||||
# cme_market_segment_id: 78
|
||||
# start_time: "00:30:00"
|
||||
# end_time: "23:30:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# sender_subid: "BTS"
|
||||
# raw_data: "S4PMA"
|
||||
# auto_fix_seq_num: true
|
||||
# }
|
||||
}
|
||||
}
|
||||
JetFIX {
|
||||
|
||||
@@ -2,4 +2,14 @@ OrdersSoftCleanupCutoff {
|
||||
value {
|
||||
extra_days: 1
|
||||
}
|
||||
}
|
||||
|
||||
SODTime
|
||||
{
|
||||
rule: "DeploymentType.type == 'dev'"
|
||||
value
|
||||
{
|
||||
sod_hh: 20
|
||||
sod_mm: 30
|
||||
}
|
||||
}
|
||||
@@ -154,6 +154,7 @@ message ICEOptions
|
||||
message ICEChannel {
|
||||
required string name = 1;
|
||||
repeated uint32 market_type = 2;
|
||||
repeated uint32 uds_market_type = 7;
|
||||
optional uint32 udp_buffer_size = 3 [default = 4194304]; //4mb
|
||||
optional uint32 heartbeat_interval = 4 [default = 36000];
|
||||
optional uint32 sequence_gap_margin = 5 [default = 10000];
|
||||
|
||||
@@ -5,6 +5,7 @@ message Ports {
|
||||
// see ports.conf for actual defaults
|
||||
optional int32 config_port = 1 ;
|
||||
optional int32 qbus_port = 2 ;
|
||||
optional int32 exchange_sim_fix_port = 3 ;
|
||||
optional int32 glbx_sim_fix_port = 3 ;
|
||||
optional int32 ice_sim_fix_port = 5 ;
|
||||
optional int32 replicator_port = 4 ;
|
||||
}
|
||||
@@ -20,4 +20,5 @@ message Symbols {
|
||||
optional SecurityExchangeList glbx = 10;
|
||||
optional SecurityExchangeList sim = 20;
|
||||
optional SecurityExchangeList ice = 30;
|
||||
optional SecurityExchangeList simice = 40;
|
||||
}
|
||||
@@ -143,11 +143,4 @@ message OffsetAttachUIOptions {
|
||||
|
||||
message ManualFillsOptions {
|
||||
optional bool modal_transactions = 1 [default = true];
|
||||
}
|
||||
|
||||
message AlgoPermissions {
|
||||
repeated string exchange_order_types = 10;
|
||||
repeated string spreader_order_types = 20;
|
||||
repeated string attachable_order_types = 30;
|
||||
repeated string outright_order_types = 40;
|
||||
}
|
||||
@@ -7,9 +7,11 @@ message JetFIX {
|
||||
required string name = 10;
|
||||
|
||||
enum JetFIXPlatform {
|
||||
GLBX = 1;
|
||||
CBOE = 6;
|
||||
SIM = 2;
|
||||
GLBX = 1;
|
||||
CBOE = 6;
|
||||
SIM = 2;
|
||||
ICE = 3;
|
||||
SIMICE = 4;
|
||||
}
|
||||
optional JetFIXPlatform platform = 15 [default = GLBX];
|
||||
|
||||
@@ -47,6 +49,7 @@ message JetFIX {
|
||||
optional string target_subid = 130 [default = ""];
|
||||
optional string sender_locationid = 135 [default = "US,NC"];
|
||||
optional string raw_data = 136 [default =""];
|
||||
optional string user_name = 138 [default =""];
|
||||
optional string self_match_prevention_id = 140 [default=""];
|
||||
optional string cti_code = 145 [default="1"];
|
||||
optional int32 customer_or_firm = 147 [default=1];
|
||||
@@ -91,6 +94,7 @@ message JetFIX {
|
||||
|
||||
message JetFIXSimConnection {
|
||||
required JetFIX.Connection sim = 10;
|
||||
required JetFIX.Connection sim_ice = 20;
|
||||
}
|
||||
|
||||
message CannedCertSession {
|
||||
|
||||
@@ -27,9 +27,10 @@ std::string descriptor(api::Security const &sec) {
|
||||
else if (sec.has_ice())
|
||||
return sec.ice().security_desc();
|
||||
else
|
||||
return "No descriptor for non glbx exchange";
|
||||
return "No descriptor for non glbx / ice exchange";
|
||||
}
|
||||
|
||||
|
||||
boost::gregorian::date smallest_leg(
|
||||
::google::protobuf::RepeatedPtrField<::bts::api::ContractLeg> const &l) {
|
||||
bts_assert(l.size());
|
||||
|
||||
@@ -182,5 +182,6 @@ inline bool gr_than(double p1, double p2, double tick_size) {
|
||||
return gr_than_eq(p1, p2, tick_size) &&
|
||||
!test_price_equality(p1,p2,tick_size);
|
||||
}
|
||||
} // namespace securities
|
||||
} // namespace bts
|
||||
|
||||
|
||||
}}
|
||||
@@ -12,6 +12,7 @@ enum Venue {
|
||||
VENUE_CBOECFE = 207;
|
||||
VENUE_GLBX = 301;
|
||||
VENUE_ICE = 306;
|
||||
VENUE_SIMICE = 3;
|
||||
}
|
||||
|
||||
enum SecurityType {
|
||||
@@ -54,11 +55,12 @@ enum CMEMics {
|
||||
}
|
||||
|
||||
enum ICEMics{
|
||||
ICE_UNSET=0;
|
||||
ICE_US = 1;
|
||||
ICE_EU = 2;
|
||||
ICE_LIFFE = 3;
|
||||
ICE_CA = 4;
|
||||
IF_UNSET = 0;
|
||||
IFU = 1;
|
||||
IFE = 2;
|
||||
IFL = 3;
|
||||
IFC = 4;
|
||||
IFEN = 5;
|
||||
}
|
||||
|
||||
enum Side {
|
||||
@@ -103,8 +105,9 @@ message CBOECFEExchangeData {
|
||||
message ICEExchangeData {
|
||||
int64 exchange_id = 10;
|
||||
string security_desc = 15; //contractSymbol
|
||||
int32 deal_display_factor = 20;
|
||||
int32 settle_display_factor = 30;
|
||||
int32 price_denominator = 17;
|
||||
int32 deal_denominator = 20;
|
||||
int32 settle_denominator = 30;
|
||||
|
||||
string market_description = 100;
|
||||
string cleared_alias = 110;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "lib/jetfix/codec/FIXBuffer.h"
|
||||
#include "lib/jetfix/codec/MessageTypes.h"
|
||||
#include "lib/jetfix/codec/FIXFragment.h"
|
||||
#include "lib/jetfix/codec/Fields.h"
|
||||
#include "lib/jetfix/codec/FieldDefinitions.h"
|
||||
#include "lib/jetfix/codec/Fields.h"
|
||||
#include "lib/jetfix/codec/MessageTypes.h"
|
||||
#include <memory>
|
||||
|
||||
#include "lib/config/protos/jetfix.pb.h"
|
||||
|
||||
@@ -14,185 +14,186 @@ namespace jetfix {
|
||||
|
||||
// Helper to batch the encoding of multiple FIX messages all sharing
|
||||
// the same FIX headers.
|
||||
class FIXEncodingStream
|
||||
{
|
||||
public:
|
||||
class FIXEncodingStream {
|
||||
public:
|
||||
FIXEncodingStream(config::JetFIX::Connection const &cfg,
|
||||
uint32_t initial_capacity = 1024*10)
|
||||
:
|
||||
_msg_header_template (),
|
||||
_header_template_size (),
|
||||
_header_template_checksum (),
|
||||
_buffer (initial_capacity),
|
||||
_message_map (),
|
||||
_current_msg (_buffer),
|
||||
_state (State::OPEN),
|
||||
_body_length_bm (),
|
||||
_msg_type_bm (),
|
||||
_seq_num_bm (),
|
||||
_last_seq_num_bm (),
|
||||
_sending_time_bm ()
|
||||
{
|
||||
_message_map.reserve (10*1024);
|
||||
uint32_t initial_capacity = 1024 * 10)
|
||||
: _msg_header_template(), _header_template_size(),
|
||||
_header_template_checksum(), _buffer(initial_capacity), _message_map(),
|
||||
_current_msg(_buffer), _state(State::OPEN), _seq_num_bm(),
|
||||
_last_seq_num_bm(), _sending_time_bm() {
|
||||
_message_map.reserve(10 * 1024);
|
||||
|
||||
FIXBuffer header_buffer (&_msg_header_template[0],_msg_header_template.size ());
|
||||
FIXFragment header (header_buffer);
|
||||
header.add<fix::BeginString>("FIX.4.2");
|
||||
FIXBuffer header_buffer(&_msg_header_template[0],
|
||||
_msg_header_template.size());
|
||||
FIXFragment header(header_buffer);
|
||||
|
||||
_body_length_bm = header.add<fix::BodyLength>(0,6);
|
||||
_msg_type_bm = header.add<fix::MsgType>(" ",1);
|
||||
_seq_num_bm = header.add<fix::MsgSeqNum>(0,9);
|
||||
_last_seq_num_bm = header.add<fix::LastSeqNumProcessed>(0,9);
|
||||
// We cannot include body lenght and msg type in the header
|
||||
// because message type is not fixed lenght, and therefore its
|
||||
// not possible to have bookmarks to fields after it, ahead of
|
||||
// knowing the message type value. The rest of the header is
|
||||
// fixed lenght so we form it here.
|
||||
_seq_num_bm = header.add<fix::MsgSeqNum>(0, 9);
|
||||
_last_seq_num_bm = header.add<fix::LastSeqNumProcessed>(0, 9);
|
||||
_sending_time_bm = header.add<SendingTimeStr>(
|
||||
"20150427-19:05:18.923",sizeof("20150427-19:05:18.923")-1);
|
||||
"20150427-19:05:18.923", sizeof("20150427-19:05:18.923") - 1);
|
||||
|
||||
header.add<fix::SenderCompID>(cfg.sender_compid ());
|
||||
header.add<fix::TargetCompId>(cfg.target_compid ());
|
||||
header.add<fix::TargetSubID>(cfg.target_subid ());
|
||||
_header_template_size = header.size ();
|
||||
_header_template_checksum = header.checksum ();
|
||||
header.add<fix::SenderCompID>(cfg.sender_compid());
|
||||
header.add<fix::TargetCompId>(cfg.target_compid());
|
||||
header.add<fix::TargetSubID>(cfg.target_subid());
|
||||
_header_template_size = header.size();
|
||||
_header_template_checksum = header.checksum();
|
||||
}
|
||||
|
||||
inline FIXFragment &new_msg (MessageTypes type)
|
||||
{
|
||||
bts_assert (_state == State::OPEN);
|
||||
tidy_last_msg ();
|
||||
|
||||
auto msg_offset = _buffer.size ();
|
||||
_message_map.emplace_back (msg_offset,0u,0u,0u,FIXFragment::Bookmark<IntField<10u>>());
|
||||
_current_msg = FIXFragment (_buffer);
|
||||
_current_msg.append (&_msg_header_template[0],
|
||||
_header_template_size,
|
||||
_header_template_checksum);
|
||||
char msg_type_str[1] = {(char) type};
|
||||
_current_msg.overwrite (_msg_type_bm.shift (msg_offset),msg_type_str,1);
|
||||
inline FIXFragment &new_msg(MessageTypes type) {
|
||||
bts_assert(_state == State::OPEN);
|
||||
tidy_last_msg();
|
||||
|
||||
auto msg_offset = _buffer.size();
|
||||
|
||||
_current_msg = FIXFragment(_buffer);
|
||||
_begin_string_bm = _current_msg.add<fix::BeginString>("FIX.4.2");
|
||||
_body_length_bm = _current_msg.add<fix::BodyLength>(0, 6);
|
||||
|
||||
char mt_encoding[4];
|
||||
auto start = encode_message_type(type, mt_encoding);
|
||||
_msg_type_bm = _current_msg.add<fix::MsgType>(
|
||||
mt_encoding + start, sizeof(mt_encoding) - start);
|
||||
|
||||
auto header_offset = _buffer.size();
|
||||
_message_map.emplace_back(msg_offset, header_offset, 0u, 0u, 0u,
|
||||
FIXFragment::Bookmark<IntField<10u>>());
|
||||
_current_msg.append(&_msg_header_template[0], _header_template_size,
|
||||
_header_template_checksum);
|
||||
return _current_msg;
|
||||
}
|
||||
|
||||
inline void close ()
|
||||
{
|
||||
bts_assert (_state == State::OPEN);
|
||||
tidy_last_msg ();
|
||||
|
||||
inline void close() {
|
||||
bts_assert(_state == State::OPEN);
|
||||
tidy_last_msg();
|
||||
_state = State::CLOSED;
|
||||
}
|
||||
|
||||
inline void reopen_empty ()
|
||||
{
|
||||
bts_assert (_state == State::CLOSED);
|
||||
bts_assert (_message_map.empty ());
|
||||
inline void reopen_empty() {
|
||||
bts_assert(_state == State::CLOSED);
|
||||
bts_assert(_message_map.empty());
|
||||
_state = State::OPEN;
|
||||
}
|
||||
|
||||
inline uint32_t size () const
|
||||
{return _buffer.size ();}
|
||||
|
||||
inline const char* data () const
|
||||
{return _buffer.data ();}
|
||||
inline uint32_t size() const { return _buffer.size(); }
|
||||
|
||||
struct MessageDesc
|
||||
{
|
||||
MessageDesc (uint32_t offset,
|
||||
uint32_t size,
|
||||
uint32_t checksum,
|
||||
uint32_t seq_num,
|
||||
FIXFragment::Bookmark<fix::Checksum> checksum_bm)
|
||||
: offset (offset),
|
||||
size (size),
|
||||
checksum (checksum),
|
||||
seq_num (seq_num),
|
||||
checksum_bm (checksum_bm)
|
||||
{}
|
||||
|
||||
inline const char *data() const { return _buffer.data(); }
|
||||
|
||||
struct MessageDesc {
|
||||
MessageDesc(uint32_t offset, uint32_t header_offset, uint32_t size,
|
||||
uint32_t checksum, uint32_t seq_num,
|
||||
FIXFragment::Bookmark<fix::Checksum> checksum_bm)
|
||||
: offset(offset), header_offset(header_offset), size(size),
|
||||
checksum(checksum), seq_num(seq_num), checksum_bm(checksum_bm) {}
|
||||
|
||||
uint32_t offset;
|
||||
uint32_t header_offset;
|
||||
uint32_t size;
|
||||
uint32_t checksum;
|
||||
uint32_t seq_num;
|
||||
FIXFragment::Bookmark<fix::Checksum> checksum_bm;
|
||||
};
|
||||
|
||||
std::string to_str () const
|
||||
{
|
||||
|
||||
std::string to_str() const {
|
||||
std::string result;
|
||||
|
||||
if (size ()) {
|
||||
|
||||
if (size()) {
|
||||
// return std::string(data(),size() is simpler but valgrind
|
||||
// reports a warning in that call
|
||||
result.resize (size ());
|
||||
std::copy (data (), data ()+size(),result.begin ());
|
||||
result.resize(size());
|
||||
std::copy(data(), data() + size(), result.begin());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_human_str () const
|
||||
{
|
||||
auto s = to_str ();
|
||||
std::replace( s.begin(), s.end(), '\001', '|' );
|
||||
std::string to_human_str() const {
|
||||
auto s = to_str();
|
||||
std::replace(s.begin(), s.end(), '\001', '|');
|
||||
return s;
|
||||
}
|
||||
|
||||
inline uint32_t stamp (uint32_t seq_num,uint32_t last_processed, std::string const&time_str)
|
||||
{
|
||||
bts_assert (_state == State::CLOSED);
|
||||
|
||||
inline uint32_t stamp(uint32_t seq_num, uint32_t last_processed,
|
||||
std::string const &time_str) {
|
||||
bts_assert(_state == State::CLOSED);
|
||||
_state = State::STAMPED;
|
||||
|
||||
for (auto &m : _message_map) {
|
||||
++seq_num;
|
||||
m.seq_num = seq_num;
|
||||
|
||||
FIXFragment frag (_buffer,m.checksum);
|
||||
frag.overwrite (_seq_num_bm.shift (m.offset),m.seq_num,9);
|
||||
frag.overwrite (_last_seq_num_bm.shift (m.offset),last_processed,9);
|
||||
frag.overwrite (_sending_time_bm.shift (m.offset),time_str);
|
||||
frag.overwrite_checksum (m.checksum_bm,frag.checksum () % 256);
|
||||
FIXFragment frag(_buffer, m.checksum);
|
||||
frag.overwrite(_seq_num_bm.shift(m.header_offset), m.seq_num, 9);
|
||||
frag.overwrite(_last_seq_num_bm.shift(m.header_offset), last_processed,
|
||||
9);
|
||||
frag.overwrite(_sending_time_bm.shift(m.header_offset), time_str);
|
||||
frag.overwrite_checksum(m.checksum_bm, frag.checksum() % 256);
|
||||
}
|
||||
return seq_num;
|
||||
}
|
||||
|
||||
inline void reset ()
|
||||
{
|
||||
_buffer.reset ();
|
||||
_message_map.clear ();
|
||||
inline void reset() {
|
||||
_buffer.reset();
|
||||
_message_map.clear();
|
||||
_state = State::OPEN;
|
||||
}
|
||||
|
||||
inline bool is_closed () const
|
||||
{return _state == State::CLOSED;}
|
||||
inline bool is_closed() const { return _state == State::CLOSED; }
|
||||
|
||||
size_t n_msgs () const {return _message_map.size ();}
|
||||
|
||||
std::vector<MessageDesc> const &msg_map () const {return _message_map;}
|
||||
private:
|
||||
std::array<char,256> _msg_header_template;
|
||||
size_t n_msgs() const { return _message_map.size(); }
|
||||
|
||||
std::vector<MessageDesc> const &msg_map() const { return _message_map; }
|
||||
|
||||
private:
|
||||
std::array<char, 256> _msg_header_template;
|
||||
uint32_t _header_template_size;
|
||||
uint32_t _header_template_checksum;
|
||||
FIXBuffer _buffer;
|
||||
std::vector<MessageDesc> _message_map;
|
||||
FIXFragment _current_msg;
|
||||
enum class State { OPEN,CLOSED,STAMPED};
|
||||
enum class State { OPEN, CLOSED, STAMPED };
|
||||
State _state;
|
||||
|
||||
|
||||
// These bookmarks point to the current msg (not the header)
|
||||
FIXFragment::Bookmark<fix::BeginString> _begin_string_bm;
|
||||
FIXFragment::Bookmark<fix::BodyLength> _body_length_bm;
|
||||
FIXFragment::Bookmark<fix::MsgType> _msg_type_bm;
|
||||
|
||||
// These bookmarks point to the header and thus have to be shifted
|
||||
// by the offset of the end of the message type.
|
||||
FIXFragment::Bookmark<fix::MsgSeqNum> _seq_num_bm;
|
||||
FIXFragment::Bookmark<fix::LastSeqNumProcessed> _last_seq_num_bm;
|
||||
typedef StringField<fix::SendingTime::tag> SendingTimeStr;
|
||||
FIXFragment::Bookmark<SendingTimeStr> _sending_time_bm;
|
||||
|
||||
inline void tidy_last_msg ()
|
||||
{
|
||||
if (_message_map.size ()) {
|
||||
auto &this_msg_map = _message_map.back ();
|
||||
auto start =
|
||||
this_msg_map.offset + _msg_type_bm.offset - fix::MsgType::tag_sz-1;
|
||||
auto end = _buffer.size ();
|
||||
_current_msg.overwrite (_body_length_bm.shift (this_msg_map.offset),
|
||||
end-start,6);
|
||||
this_msg_map.checksum = _current_msg.checksum ();
|
||||
this_msg_map.checksum_bm = _current_msg.add_checksum (0);
|
||||
this_msg_map.size = _buffer.size () - this_msg_map.offset;
|
||||
inline void tidy_last_msg() {
|
||||
if (_message_map.size()) {
|
||||
auto &this_msg_map = _message_map.back();
|
||||
auto start = _msg_type_bm.offset - fix::MsgType::tag_sz - 1;
|
||||
auto end = _buffer.size();
|
||||
_current_msg.overwrite(_body_length_bm, end - start, 6);
|
||||
this_msg_map.checksum = _current_msg.checksum();
|
||||
this_msg_map.checksum_bm = _current_msg.add_checksum(0);
|
||||
this_msg_map.size = _buffer.size() - this_msg_map.offset;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t encode_message_type(MessageTypes m, char out[4]) {
|
||||
auto mt = (uint32_t)m;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
out[i] = mt >> (8 * (3 - i));
|
||||
mt &= ((1 << (8 * (3 - i))) - 1);
|
||||
}
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (out[i])
|
||||
return i;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
} // namespace jetfix
|
||||
} // namespace bts
|
||||
@@ -69,6 +69,9 @@ typedef StringField<143> TargetLocationID;
|
||||
typedef StringField<1603> ApplicationSystemName;
|
||||
typedef StringField<1604> ApplicationSystemVersion;
|
||||
typedef StringField<1605> ApplicationSystemVendor;
|
||||
typedef StringField<9450> ICEApplicationSystemName;
|
||||
typedef StringField<9451> ICEApplicationSystemVersion;
|
||||
typedef StringField<9452> ICEApplicationSystemVendor;
|
||||
typedef StringField<167> SecurityType;
|
||||
typedef StringField<17> ExecID;
|
||||
typedef StringField<19> ExecRefID;
|
||||
@@ -97,6 +100,7 @@ typedef StringField<7928> SelfMatchPreventionID;
|
||||
typedef StringField<8> BeginString;
|
||||
typedef StringField<9324> OrderOptionalData;
|
||||
typedef StringField<96> RawData;
|
||||
typedef StringField<553> UserName;
|
||||
typedef StringField<9717> CorrelationClOrdID;
|
||||
typedef StringField<9771> MMAccount;
|
||||
typedef TimeField<122> OrigSendingTime;
|
||||
@@ -104,6 +108,38 @@ typedef TimeField<52> SendingTime;
|
||||
typedef TimeField<5979> RequestTime;
|
||||
typedef TimeField<60> TransactTime;
|
||||
|
||||
//ICE
|
||||
typedef IntField<9208> Int_CtiCode;
|
||||
typedef BigIntField<11> Int_ClOrdID;
|
||||
typedef BigIntField<37> Int_OrderID;
|
||||
typedef BigIntField<41> Int_OrigClOrdID;
|
||||
typedef IntField<109> CompanyID;
|
||||
typedef IntField<55> Int_Symbol;
|
||||
typedef IntField<439> Int_ClearingFirm;
|
||||
typedef StringField<9121> Memo;
|
||||
typedef IntField<103> OrdRejReason;
|
||||
typedef IntField<285> DeleteReason;
|
||||
typedef CharField<9195> AccountCode;
|
||||
typedef StringField<9207> CustomerAccountRefId;
|
||||
typedef StringField<115> OnBehalfOfCompID;
|
||||
typedef StringField<116> OnBehalfOfSubID;
|
||||
typedef StringField<144> OnBehalfOfLocationID;
|
||||
typedef StringField<9139> OriginatorUserID;
|
||||
typedef CharField<18> ExecInst;
|
||||
typedef IntField<210> MaxShow;
|
||||
typedef IntField<9006> ICEStrategyPreference;
|
||||
typedef IntField<9007> ICETimeStampPreference;
|
||||
typedef StringField<1031> CustOrderHandlingInst;
|
||||
|
||||
typedef IntField<9700> MifidDirectElectronicAccess;
|
||||
typedef IntField<9701> MifidTradingCapacity;
|
||||
typedef IntField<9702> MifidLiquidityProvision;
|
||||
typedef IntField<9703> MifidCommodityDerivIndicator;
|
||||
typedef BigIntField<9704> MifidInvestmentDecision;
|
||||
typedef BigIntField<9705> MifidExecutionDecision;
|
||||
typedef BigIntField<9706> MifidClientIDCode;
|
||||
typedef BigIntField<9707> MifidId;
|
||||
|
||||
typedef Group<NoQuoteEntries,
|
||||
QuoteEntryID,
|
||||
Symbol,
|
||||
|
||||
@@ -156,6 +156,33 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <uint16_t tag>
|
||||
class BigIntField : public BaseField<tag,int64_t>
|
||||
{
|
||||
public:
|
||||
typedef BaseField<tag,int64_t> Parent;
|
||||
|
||||
void read (ReaderCursor &cursor)
|
||||
{
|
||||
auto loc = cursor.read_field ();
|
||||
Parent::_value = atoll (&(cursor.data ()[loc.first]));
|
||||
}
|
||||
|
||||
static uint32_t max_value_size (int64_t,int pad = 0)
|
||||
{
|
||||
if (pad == 0)
|
||||
return 20;
|
||||
else
|
||||
return pad;
|
||||
}
|
||||
|
||||
static std::pair<uint32_t,uint32_t> write (char*buffer,int64_t i,int pad = 0)
|
||||
{
|
||||
auto written = i64_toa (i,buffer,pad);
|
||||
return std::make_pair (written,sum_bytes (buffer,written));
|
||||
}
|
||||
};
|
||||
|
||||
template <uint16_t tag>
|
||||
class StringField : public BaseField<tag,std::string>
|
||||
{
|
||||
|
||||
@@ -66,5 +66,58 @@ typedef FIXMsg<MessageTypes::CancelReject,
|
||||
CorrelationClOrdID>
|
||||
CancelRejectMsg;
|
||||
|
||||
typedef FIXMsg<MessageTypes::ICETraderLoginResponse,
|
||||
CompanyID,
|
||||
UserName,
|
||||
Text>
|
||||
ICETraderLoginResponseMsg;
|
||||
|
||||
typedef FIXMsg<MessageTypes::ICETraderLogoutResponse,
|
||||
CompanyID,
|
||||
UserName,
|
||||
Text>
|
||||
ICETraderLogoutResponseMsg;
|
||||
|
||||
typedef FIXMsg<MessageTypes::ExecutionReport,
|
||||
Int_OrderID,
|
||||
Int_ClOrdID,
|
||||
CompanyID,
|
||||
ExecID,
|
||||
ExecRefID,
|
||||
ExecType,
|
||||
OrdStatus,
|
||||
OrdRejReason,
|
||||
Int_Symbol,
|
||||
Side,
|
||||
OrderQty,
|
||||
MaxShow,
|
||||
OrdType,
|
||||
Price,
|
||||
StopPx,
|
||||
TimeInForce,
|
||||
LeavesQty,
|
||||
CumQty,
|
||||
AvgPx,
|
||||
LastPx,
|
||||
LastShares,
|
||||
TransactTimeStr,
|
||||
MultiLegReportingType,
|
||||
ClearingAccount,
|
||||
Memo,
|
||||
Text,
|
||||
DeleteReason,
|
||||
TargetSubID,
|
||||
MsgSeqNum>
|
||||
ICEExecutionReportMsg;
|
||||
|
||||
typedef FIXMsg<MessageTypes::CancelReject,
|
||||
Int_OrderID,
|
||||
Int_ClOrdID,
|
||||
Int_OrigClOrdID,
|
||||
CXlRejReason,
|
||||
Text,
|
||||
Memo>
|
||||
ICECancelRejectMsg;
|
||||
|
||||
}}}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace bts {
|
||||
namespace jetfix {
|
||||
|
||||
enum class MessageTypes
|
||||
enum class MessageTypes : uint32_t
|
||||
{
|
||||
Advertisement = '7',
|
||||
Allocation = 'J',
|
||||
@@ -48,7 +48,12 @@ enum class MessageTypes
|
||||
SettlementInstructions = 'T',
|
||||
TestRequest = '1',
|
||||
TradingSessionStatus = 'h',
|
||||
TradingSessionStatusRequest = 'g'
|
||||
TradingSessionStatusRequest = 'g',
|
||||
ICETraderLogin = ('U' << 16) + ('C' << 8) + 'G',
|
||||
ICETraderLoginResponse = ('U' << 16) + ('C' << 8) + 'I',
|
||||
ICETraderLogout = ('U' << 16) + ('C' << 8) + 'H',
|
||||
ICETraderLogoutResponse = ('U' << 16) + ('C' << 8) + 'J',
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
@@ -259,3 +259,199 @@ inline int u32_toa(uint32_t u, char* buffer, int pad) {
|
||||
}
|
||||
|
||||
|
||||
///https://github.com/miloyip/itoa-benchmark
|
||||
|
||||
#define BEGIN2(n) \
|
||||
do { \
|
||||
int t = (n); \
|
||||
if(t < 10) *p++ = '0' + t; \
|
||||
else { \
|
||||
t *= 2; \
|
||||
*p++ = gDigitsLut[t]; \
|
||||
*p++ = gDigitsLut[t + 1]; \
|
||||
} \
|
||||
} while(0)
|
||||
#define MIDDLE2(n) \
|
||||
do { \
|
||||
int t = (n) * 2; \
|
||||
*p++ = gDigitsLut[t]; \
|
||||
*p++ = gDigitsLut[t + 1]; \
|
||||
} while(0)
|
||||
#define BEGIN4(n) \
|
||||
do { \
|
||||
int t4 = (n); \
|
||||
if(t4 < 100) BEGIN2(t4); \
|
||||
else { BEGIN2(t4 / 100); MIDDLE2(t4 % 100); } \
|
||||
} while(0)
|
||||
#define MIDDLE4(n) \
|
||||
do { \
|
||||
int t4 = (n); \
|
||||
MIDDLE2(t4 / 100); MIDDLE2(t4 % 100); \
|
||||
} while(0)
|
||||
#define BEGIN8(n) \
|
||||
do { \
|
||||
uint32_t t8 = (n); \
|
||||
if(t8 < 10000) BEGIN4(t8); \
|
||||
else { BEGIN4(t8 / 10000); MIDDLE4(t8 % 10000); } \
|
||||
} while(0)
|
||||
#define MIDDLE8(n) \
|
||||
do { \
|
||||
uint32_t t8 = (n); \
|
||||
MIDDLE4(t8 / 10000); MIDDLE4(t8 % 10000); \
|
||||
} while(0)
|
||||
#define MIDDLE16(n) \
|
||||
do { \
|
||||
uint64_t t16 = (n); \
|
||||
MIDDLE8(t16 / 100000000); MIDDLE8(t16 % 100000000); \
|
||||
} while(0)
|
||||
|
||||
inline int u64_toa(uint64_t value, char* p)
|
||||
{
|
||||
auto start = p;
|
||||
if(value < 100000000) BEGIN8(value);
|
||||
else if(value < 10000000000000000) { BEGIN8(value / 100000000); MIDDLE8(value % 100000000); }
|
||||
else { BEGIN4(value / 10000000000000000); MIDDLE16(value % 10000000000000000); }
|
||||
*p = 0;
|
||||
return p-start;
|
||||
}
|
||||
|
||||
inline int count_digits (int64_t value)
|
||||
{
|
||||
static auto P01 = 10ull;
|
||||
static auto P02 = P01*10;
|
||||
static auto P03 = P02*10;
|
||||
static auto P04 = P03*10;
|
||||
static auto P05 = P04*10;
|
||||
static auto P06 = P05*10;
|
||||
static auto P07 = P06*10;
|
||||
static auto P08 = P07*10;
|
||||
static auto P09 = P08*10;
|
||||
static auto P10 = P09*10;
|
||||
static auto P11 = P10*10;
|
||||
static auto P12 = P11*10;
|
||||
static auto P13 = P12*10;
|
||||
static auto P14 = P13*10;
|
||||
static auto P15 = P14*10;
|
||||
static auto P16 = P15*10;
|
||||
static auto P17 = P16*10;
|
||||
static auto P18 = P17*10;
|
||||
static auto P19 = P18*10;
|
||||
|
||||
uint64_t u = static_cast<uint64_t>(value);
|
||||
if (value < 0)
|
||||
u = ~u + 1;
|
||||
|
||||
if (u < P01) return 1;
|
||||
if (u < P02) return 2;
|
||||
if (u < P03) return 3;
|
||||
if (u < P04) return 4;
|
||||
if (u < P05) return 5;
|
||||
if (u < P06) return 6;
|
||||
if (u < P07) return 7;
|
||||
if (u < P08) return 8;
|
||||
if (u < P09) return 9;
|
||||
if (u < P10) return 10;
|
||||
if (u < P11) return 11;
|
||||
if (u < P12) return 12;
|
||||
if (u < P13) return 13;
|
||||
if (u < P14) return 14;
|
||||
if (u < P15) return 15;
|
||||
if (u < P16) return 16;
|
||||
if (u < P17) return 17;
|
||||
if (u < P18) return 18;
|
||||
if (u < P19) return 19;
|
||||
return 20;
|
||||
}
|
||||
|
||||
inline int count_digits (uint64_t u)
|
||||
{
|
||||
static auto P01 = 10ull;
|
||||
static auto P02 = P01*10;
|
||||
static auto P03 = P02*10;
|
||||
static auto P04 = P03*10;
|
||||
static auto P05 = P04*10;
|
||||
static auto P06 = P05*10;
|
||||
static auto P07 = P06*10;
|
||||
static auto P08 = P07*10;
|
||||
static auto P09 = P08*10;
|
||||
static auto P10 = P09*10;
|
||||
static auto P11 = P10*10;
|
||||
static auto P12 = P11*10;
|
||||
static auto P13 = P12*10;
|
||||
static auto P14 = P13*10;
|
||||
static auto P15 = P14*10;
|
||||
static auto P16 = P15*10;
|
||||
static auto P17 = P16*10;
|
||||
static auto P18 = P17*10;
|
||||
static auto P19 = P18*10;
|
||||
|
||||
if (u < P01) return 1;
|
||||
if (u < P02) return 2;
|
||||
if (u < P03) return 3;
|
||||
if (u < P04) return 4;
|
||||
if (u < P05) return 5;
|
||||
if (u < P06) return 6;
|
||||
if (u < P07) return 7;
|
||||
if (u < P08) return 8;
|
||||
if (u < P09) return 9;
|
||||
if (u < P10) return 10;
|
||||
if (u < P11) return 11;
|
||||
if (u < P12) return 12;
|
||||
if (u < P13) return 13;
|
||||
if (u < P14) return 14;
|
||||
if (u < P15) return 15;
|
||||
if (u < P16) return 16;
|
||||
if (u < P17) return 17;
|
||||
if (u < P18) return 18;
|
||||
if (u < P19) return 19;
|
||||
return 20;
|
||||
}
|
||||
|
||||
inline int i64_toa(int64_t value, char* buffer, int pad)
|
||||
{
|
||||
auto start = buffer;
|
||||
uint64_t u = static_cast<uint64_t>(value);
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
u = ~u + 1;
|
||||
}
|
||||
if (pad)
|
||||
{
|
||||
auto digits = count_digits (value);
|
||||
auto offset = pad - digits;
|
||||
if (offset > 0)
|
||||
{
|
||||
auto start = buffer + offset;
|
||||
while (buffer != start)
|
||||
{
|
||||
*buffer='0';
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
else if (offset < 0)
|
||||
return 0;
|
||||
}
|
||||
return (buffer-start) + u64_toa(u, buffer);
|
||||
}
|
||||
|
||||
inline int u64_toa(uint64_t u, char* buffer, int pad)
|
||||
{
|
||||
auto start = buffer;
|
||||
if (pad)
|
||||
{
|
||||
auto digits = count_digits (u);
|
||||
auto offset = pad - digits;
|
||||
if (offset > 0)
|
||||
{
|
||||
auto start = buffer + offset;
|
||||
while (buffer != start)
|
||||
{
|
||||
*buffer='0';
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
else if (offset < 0)
|
||||
return 0;
|
||||
}
|
||||
return (buffer-start) + u64_toa(u, buffer);
|
||||
}
|
||||
@@ -783,42 +783,63 @@ OutFIXPtr make_logon(uint32_t seq_num, uint32_t last_seq_num_processed,
|
||||
const char *application = "O2";
|
||||
#endif
|
||||
|
||||
buffer.add<ApplicationSystemName>(application);
|
||||
buffer.add<ApplicationSystemVersion>("1.0");
|
||||
buffer.add<ApplicationSystemVendor>("BTS");
|
||||
|
||||
if (session_cfg.has_trading_session_id()) {
|
||||
buffer.add<fix::NoTradingSessions>(1);
|
||||
buffer.add<fix::TradingSessionID>(session_cfg.trading_session_id());
|
||||
}
|
||||
if (session_cfg.has_udf_support_indicator())
|
||||
buffer.add<fix::UDFSupportIndicator>(session_cfg.udf_support_indicator());
|
||||
|
||||
if (session_cfg.use_cme_secure_logon()) {
|
||||
bts_assert(session_cfg.sender_compid().size() >= 3);
|
||||
auto session_id = session_cfg.sender_compid().substr(0, 3);
|
||||
std::string seq_num_str(9, ' ');
|
||||
i32_toa(seq_num, &seq_num_str[0], 9);
|
||||
|
||||
std::string last_seq_num_str(9, ' ');
|
||||
i32_toa(last_seq_num_processed, &last_seq_num_str[0], 9);
|
||||
auto ld = glbx::calculate_hmac(
|
||||
session_id, seq_num_str, session_cfg.sender_compid(),
|
||||
session_cfg.sender_subid(), time_str, session_cfg.target_subid(),
|
||||
std::to_string(session_cfg.seconds_between_hbs()),
|
||||
session_cfg.sender_locationid(), last_seq_num_str, application, "1.0",
|
||||
"BTS");
|
||||
#ifndef BTS_EDGE
|
||||
LOG(Jetfix, Info, "Canonical string for secure logon: {}", ld.canonical);
|
||||
#endif
|
||||
buffer.add<EncodedTextLen>(ld.access_key.size());
|
||||
buffer.add<EncodedText>(ld.access_key);
|
||||
buffer.add<EncryptedPasswordMethod>("CME-1-SHA-256");
|
||||
buffer.add<EncryptedPasswordLen>(ld.signature.size());
|
||||
buffer.add<EncryptedPassword>(ld.signature);
|
||||
} else {
|
||||
if(session_cfg.platform() == bts::config::JetFIX_Connection_JetFIXPlatform_ICE ||
|
||||
session_cfg.platform() == bts::config::JetFIX_Connection_JetFIXPlatform_SIMICE)
|
||||
{
|
||||
buffer.add<ICEApplicationSystemName>(application);
|
||||
buffer.add<ICEApplicationSystemVersion>("1.0");
|
||||
buffer.add<ICEApplicationSystemVendor>("BTS");
|
||||
|
||||
buffer.add<UserName>(session_cfg.user_name());
|
||||
buffer.add<RawDataLength>(session_cfg.raw_data().size());
|
||||
buffer.add<RawData>(session_cfg.raw_data());
|
||||
buffer.add<RawData>(session_cfg.raw_data());
|
||||
buffer.add<EncryptMethod>(0);
|
||||
buffer.add<ICEStrategyPreference>(1);
|
||||
buffer.add<ICETimeStampPreference>(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.add<ApplicationSystemName>(application);
|
||||
buffer.add<ApplicationSystemVersion>("1.0");
|
||||
buffer.add<ApplicationSystemVendor>("BTS");
|
||||
|
||||
if (session_cfg.has_trading_session_id()) {
|
||||
buffer.add<fix::NoTradingSessions>(1);
|
||||
buffer.add<fix::TradingSessionID>(session_cfg.trading_session_id());
|
||||
}
|
||||
if (session_cfg.has_udf_support_indicator())
|
||||
buffer.add<fix::UDFSupportIndicator>(session_cfg.udf_support_indicator());
|
||||
|
||||
if (session_cfg.use_cme_secure_logon()) {
|
||||
bts_assert(session_cfg.sender_compid().size() >= 3);
|
||||
auto session_id = session_cfg.sender_compid().substr(0, 3);
|
||||
std::string seq_num_str(9, ' ');
|
||||
i32_toa(seq_num, &seq_num_str[0], 9);
|
||||
|
||||
std::string last_seq_num_str(9, ' ');
|
||||
i32_toa(last_seq_num_processed, &last_seq_num_str[0], 9);
|
||||
auto ld = glbx::calculate_hmac(
|
||||
session_id, seq_num_str, session_cfg.sender_compid(),
|
||||
session_cfg.sender_subid(), time_str, session_cfg.target_subid(),
|
||||
std::to_string(session_cfg.seconds_between_hbs()),
|
||||
session_cfg.sender_locationid(), last_seq_num_str, application, "1.0",
|
||||
"BTS");
|
||||
#ifndef BTS_EDGE
|
||||
LOG(Jetfix, Info, "Canonical string for secure logon: {}", ld.canonical);
|
||||
#endif
|
||||
buffer.add<EncodedTextLen>(ld.access_key.size());
|
||||
buffer.add<EncodedText>(ld.access_key);
|
||||
buffer.add<EncryptedPasswordMethod>("CME-1-SHA-256");
|
||||
buffer.add<EncryptedPasswordLen>(ld.signature.size());
|
||||
buffer.add<EncryptedPassword>(ld.signature);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.add<RawDataLength>(session_cfg.raw_data().size());
|
||||
buffer.add<RawData>(session_cfg.raw_data());
|
||||
if(session_cfg.user_name() != "")
|
||||
buffer.add<UserName>(session_cfg.user_name());
|
||||
}
|
||||
}
|
||||
|
||||
stream.close();
|
||||
|
||||
@@ -293,7 +293,7 @@ TimeStamp copy_synthetic_depth(const SyntheticStrategy& synth, size_t count, Pri
|
||||
// END SYNTHETIC DEPTH
|
||||
/////////////////////////////
|
||||
|
||||
bool MDConsumerHandle::get_last_trade(TimeStamp& time, PriceSize& trade, datetime::LLDateTime& trade_timestamp, size_t* total_volume) const {
|
||||
bool MDConsumerHandle::get_last_trade(TimeStamp& time, PriceSize& trade, datetime::LLDateTime& trade_timestamp, size_t* total_volume, int* from_spread) const {
|
||||
switch(_type) {
|
||||
case HANDLETYPE_VOID: return false;
|
||||
case HANDLETYPE_DEPTH:
|
||||
@@ -303,6 +303,7 @@ bool MDConsumerHandle::get_last_trade(TimeStamp& time, PriceSize& trade, datetim
|
||||
if (result) {
|
||||
trade_timestamp = pcold->last_trade_time;
|
||||
if (total_volume) { *total_volume = pcold->total_volume; }
|
||||
if (from_spread) { *from_spread = pcold->from_spread; }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ public:
|
||||
return get_book(read_combined, time, copydepth, bids, asks);
|
||||
}
|
||||
|
||||
bool get_last_trade(TimeStamp& time, PriceSize& out_trade, datetime::LLDateTime& out_trade_timestamp, size_t* total_volume=nullptr) const;
|
||||
bool get_last_trade(TimeStamp& time, PriceSize& out_trade, datetime::LLDateTime& out_trade_timestamp, size_t* total_volume=nullptr,int* from_spread=nullptr) const;
|
||||
|
||||
IntPrice settlement_price() const {
|
||||
switch(_type) {
|
||||
|
||||
@@ -101,8 +101,9 @@ void MDProducerHandle::set_status(CoconutSecurityStatus status) {
|
||||
}
|
||||
}
|
||||
|
||||
void MDProducerHandle::add_trade(TimeStamp time, const PriceSize price, LLDateTime tradetime, co2::AggressorSide agside, uint32_t volume) {
|
||||
// Add this trade to the last trade if price match
|
||||
void MDProducerHandle::add_trade(TimeStamp time, const PriceSize price, LLDateTime tradetime,
|
||||
co2::AggressorSide agside, uint32_t volume, bool from_spread) {
|
||||
// Add this trade to the last trade if price/side match
|
||||
auto current = std::get<PriceSize>(cdata().last_trade.load());
|
||||
if (current.int_price() == price.int_price()) {
|
||||
cdata().last_trade.store(PriceSize { price.int_price(), price.size() + current.size() }, time);
|
||||
@@ -111,7 +112,9 @@ void MDProducerHandle::add_trade(TimeStamp time, const PriceSize price, LLDateTi
|
||||
cdata().last_trade.store(price,time);
|
||||
}
|
||||
cdata().last_trade_time = tradetime;
|
||||
cdata().total_volume = volume;
|
||||
cdata().from_spread = (from_spread ? 1 : 0);
|
||||
if (volume > 0)
|
||||
cdata().total_volume = volume;
|
||||
|
||||
if (key() != invalid_security_key) {
|
||||
co2::TradeMessage trade;
|
||||
@@ -125,9 +128,15 @@ void MDProducerHandle::add_trade(TimeStamp time, const PriceSize price, LLDateTi
|
||||
_channel.add_trade(trade);
|
||||
}
|
||||
}
|
||||
void MDProducerHandle::set_last_trade(TimeStamp time, const PriceSize ps, datetime::LLDateTime tradetime, uint32_t total_volume) {
|
||||
void MDProducerHandle::set_last_trade(TimeStamp time, const PriceSize ps, datetime::LLDateTime tradetime, uint32_t total_volume, bool from_spread) {
|
||||
cdata().last_trade.store(ps,time);
|
||||
cdata().last_trade_time = tradetime;
|
||||
cdata().from_spread = (from_spread ? 1 : 0);
|
||||
if(total_volume > 0)
|
||||
cdata().total_volume = total_volume;
|
||||
}
|
||||
|
||||
void MDProducerHandle::set_total_volume(uint32_t total_volume) {
|
||||
cdata().total_volume = total_volume;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,9 +92,11 @@ 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, co2::AggressorSide agside, 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, bool from_spread=false); // 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 set_last_trade(TimeStamp time, const PriceSize ps, datetime::LLDateTime date, uint32_t total_volume=0,bool from_spread=false);
|
||||
void set_total_volume(uint32_t total_volume);
|
||||
void add_rfq(TimeStamp time, const co2::QuoteRequestMessage& rfq); // cold
|
||||
|
||||
void update_exchange_status(TimeStamp time, TradingStatus status); // cold
|
||||
|
||||
@@ -90,7 +90,7 @@ void add_symbols_to_result(
|
||||
|
||||
size_t get_system_md_symbols(api::Venue exchange, SecurityType type,
|
||||
std::set<UserSymbol> &result) {
|
||||
bts_assert(config::system_symbols::Symbols::descriptor()->field_count() == 3);
|
||||
bts_assert(config::system_symbols::Symbols::descriptor()->field_count() == 4);
|
||||
{
|
||||
auto const &e = config::get<config::system_symbols::Symbols>().glbx();
|
||||
if (exchange == api::VENUE_UNSET || exchange == api::VENUE_GLBX) {
|
||||
@@ -146,34 +146,47 @@ size_t get_system_md_symbols(api::Venue exchange, SecurityType type,
|
||||
|
||||
{
|
||||
auto const &e = config::get<config::system_symbols::Symbols>().sim();
|
||||
if (exchange == api::VENUE_UNSET || exchange == api::VENUE_SIM) {
|
||||
if (type == api::SECURITYTYPE_FUTURE ||
|
||||
type == api::SECURITYTYPE_UNSET) {
|
||||
add_symbols_to_result(e.future(), api::VENUE_SIM,
|
||||
api::SECURITYTYPE_FUTURE, &result);
|
||||
}
|
||||
if (type == api::SECURITYTYPE_OPTION ||
|
||||
type == api::SECURITYTYPE_UNSET) {
|
||||
add_symbols_to_result(e.option(), api::VENUE_SIM,
|
||||
api::SECURITYTYPE_OPTION, &result);
|
||||
}
|
||||
if (type == api::SECURITYTYPE_SPREAD ||
|
||||
type == api::SECURITYTYPE_UNSET) {
|
||||
add_symbols_to_result(e.spread(), api::VENUE_SIM,
|
||||
api::SECURITYTYPE_SPREAD, &result);
|
||||
}
|
||||
if (exchange == api::VENUE_UNSET || exchange == api::VENUE_SIM)
|
||||
{
|
||||
if (type == api::SECURITYTYPE_FUTURE || type == api::SECURITYTYPE_UNSET)
|
||||
add_symbols_to_result(e.future(), api::VENUE_SIM, api::SECURITYTYPE_FUTURE, &result);
|
||||
if (type == api::SECURITYTYPE_OPTION || type == api::SECURITYTYPE_UNSET)
|
||||
add_symbols_to_result(e.option(), api::VENUE_SIM, api::SECURITYTYPE_OPTION, &result);
|
||||
if (type == api::SECURITYTYPE_SPREAD || type == api::SECURITYTYPE_UNSET)
|
||||
add_symbols_to_result(e.spread(), api::VENUE_SIM, api::SECURITYTYPE_SPREAD, &result);
|
||||
}
|
||||
if (exchange == api::VENUE_BTS || exchange == api::VENUE_UNSET) {
|
||||
if (exchange == api::VENUE_BTS || exchange == api::VENUE_UNSET)
|
||||
{
|
||||
std::set<std::string> all_symbols;
|
||||
all_symbols.insert(e.future().begin(), e.future().end());
|
||||
all_symbols.insert(e.option().begin(), e.option().end());
|
||||
all_symbols.insert(e.spread().begin(), e.spread().end());
|
||||
for (const auto &symbol : all_symbols) {
|
||||
result.insert(UserSymbol(symbol, api::VENUE_BTS,
|
||||
api::SECURITYTYPE_SYNTHETIC));
|
||||
}
|
||||
for (const auto &symbol : all_symbols)
|
||||
result.insert(UserSymbol(symbol, api::VENUE_BTS, api::SECURITYTYPE_SYNTHETIC));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto const &e = config::get<config::system_symbols::Symbols>().simice();
|
||||
if (exchange == api::VENUE_UNSET || exchange == api::VENUE_SIMICE)
|
||||
{
|
||||
if (type == api::SECURITYTYPE_FUTURE || type == api::SECURITYTYPE_UNSET)
|
||||
add_symbols_to_result(e.future(), api::VENUE_SIMICE, api::SECURITYTYPE_FUTURE, &result);
|
||||
if (type == api::SECURITYTYPE_OPTION || type == api::SECURITYTYPE_UNSET)
|
||||
add_symbols_to_result(e.option(), api::VENUE_SIMICE, api::SECURITYTYPE_OPTION, &result);
|
||||
if (type == api::SECURITYTYPE_SPREAD || type == api::SECURITYTYPE_UNSET)
|
||||
add_symbols_to_result(e.spread(), api::VENUE_SIMICE, api::SECURITYTYPE_SPREAD, &result);
|
||||
}
|
||||
if (exchange == api::VENUE_BTS || exchange == api::VENUE_UNSET)
|
||||
{
|
||||
std::set<std::string> all_symbols;
|
||||
all_symbols.insert(e.future().begin(), e.future().end());
|
||||
all_symbols.insert(e.option().begin(), e.option().end());
|
||||
all_symbols.insert(e.spread().begin(), e.spread().end());
|
||||
for (const auto &symbol : all_symbols)
|
||||
result.insert(UserSymbol(symbol, api::VENUE_BTS, api::SECURITYTYPE_SYNTHETIC));
|
||||
}
|
||||
}
|
||||
|
||||
return result.size();
|
||||
}
|
||||
|
||||
@@ -31,8 +31,9 @@ FixedSecurity::FixedSecurity() :
|
||||
cme_main_fraction(0),
|
||||
cme_sub_fraction(0),
|
||||
cme_price_display_format(0),
|
||||
ice_deal_display_factor(0),
|
||||
ice_settle_display_factor(0),
|
||||
ice_price_denominator(0),
|
||||
ice_deal_denominator(0),
|
||||
ice_settle_denominator(0),
|
||||
_symbol(),
|
||||
_cfi_code(),
|
||||
_security_desc(),
|
||||
@@ -99,7 +100,10 @@ void write_leg_descriptor(std::ostringstream& result, char separator, const api:
|
||||
std::string security_descriptor(const api::Security& security) {
|
||||
const char separator = ' ';
|
||||
std::ostringstream result;
|
||||
result << security.symbol() << separator << Venue_Name(security.exchange());
|
||||
if(security.exchange() == Venue::VENUE_ICE || security.exchange() == Venue::VENUE_SIMICE)
|
||||
result << security.ice().security_desc() << separator << Venue_Name(security.exchange());
|
||||
else
|
||||
result << security.symbol() << separator << Venue_Name(security.exchange());
|
||||
switch(security.Contract_case()) {
|
||||
case Security::ContractCase::kOption: {
|
||||
result << separator;
|
||||
@@ -181,8 +185,9 @@ void convert_security(const FixedSecurity& source, Security* presult) {
|
||||
case Venue::VENUE_ICE:
|
||||
dest.mutable_ice()->set_exchange_id(source.numeric_id);
|
||||
dest.mutable_ice()->set_security_desc(source.security_desc());
|
||||
dest.mutable_ice()->set_deal_display_factor(source.ice_deal_display_factor);
|
||||
dest.mutable_ice()->set_settle_display_factor(source.ice_settle_display_factor);
|
||||
dest.mutable_ice()->set_price_denominator(source.ice_price_denominator);
|
||||
dest.mutable_ice()->set_deal_denominator(source.ice_deal_denominator);
|
||||
dest.mutable_ice()->set_settle_denominator(source.ice_settle_denominator);
|
||||
|
||||
dest.mutable_ice()->set_market_description(source.ice_market_description());
|
||||
dest.mutable_ice()->set_cleared_alias(source.ice_cleared_alias());
|
||||
@@ -312,8 +317,9 @@ void convert_security(const Security& src, FixedSecurity& dest, bool set_securit
|
||||
case Security::ExchangeDataCase::kIce:
|
||||
dest.numeric_id = src.ice().exchange_id();
|
||||
dest.security_desc(src.ice().security_desc());
|
||||
dest.ice_deal_display_factor = src.ice().deal_display_factor();
|
||||
dest.ice_settle_display_factor = src.ice().settle_display_factor();
|
||||
dest.ice_price_denominator = src.ice().price_denominator();
|
||||
dest.ice_deal_denominator = src.ice().deal_denominator();
|
||||
dest.ice_settle_denominator = src.ice().settle_denominator();
|
||||
|
||||
dest.ice_market_description(src.ice().market_description());
|
||||
dest.ice_cleared_alias(src.ice().cleared_alias());
|
||||
|
||||
@@ -59,8 +59,9 @@ public:
|
||||
uint8_t cme_main_fraction;
|
||||
uint8_t cme_sub_fraction;
|
||||
uint8_t cme_price_display_format;
|
||||
int8_t ice_deal_display_factor;
|
||||
int8_t ice_settle_display_factor;
|
||||
int8_t ice_price_denominator;
|
||||
int8_t ice_deal_denominator;
|
||||
int8_t ice_settle_denominator;
|
||||
|
||||
STRING_PROPERTY(ice_market_description);
|
||||
STRING_PROPERTY(ice_cleared_alias);
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace md {
|
||||
|
||||
using utils::TimeStamp;
|
||||
|
||||
const uint32_t shm_version = 102;
|
||||
const uint32_t shm_version = 107;
|
||||
|
||||
struct ALIGNED_(CACHE_LINE) HotHeader {
|
||||
size_t count;
|
||||
@@ -213,9 +213,10 @@ struct ColdEntry {
|
||||
exchange_status(co2::TRADINGSTATUS_UNKNOWN),
|
||||
last_trade(),
|
||||
total_volume(0),
|
||||
last_trade_time(),
|
||||
last_trade_time(),
|
||||
misc(),
|
||||
deleted(false)
|
||||
from_spread(0),
|
||||
deleted(0)
|
||||
{
|
||||
this->security.size = security_size;
|
||||
}
|
||||
@@ -227,12 +228,13 @@ struct ColdEntry {
|
||||
|
||||
// Last Trade
|
||||
AtomicPriceSize last_trade;
|
||||
size_t total_volume;
|
||||
size_t total_volume;
|
||||
datetime::LLDateTime last_trade_time;
|
||||
|
||||
|
||||
MiscData misc;
|
||||
|
||||
bool deleted;
|
||||
int from_spread;
|
||||
int deleted;
|
||||
FixedSecurity security;
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ std::string ICEChannel::to_string() const
|
||||
std::string mt = name;
|
||||
for(const auto& x : market_types)
|
||||
mt += " " + std::to_string(x);
|
||||
for(const auto& x : uds_market_types)
|
||||
mt += " " + std::to_string(x);
|
||||
return mt;
|
||||
}
|
||||
|
||||
@@ -45,6 +47,9 @@ const vector<ICEChannel> parse_ice_channels(const vector<UserSymbol>& symbols)
|
||||
chan.symbols.insert(symbols.begin(), symbols.end());
|
||||
for(const auto& xx : x.market_type())
|
||||
chan.market_types.push_back(xx);
|
||||
for(const auto& xx : x.uds_market_type())
|
||||
chan.uds_market_types.push_back(xx);
|
||||
|
||||
result.push_back(chan);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -13,6 +13,7 @@ struct ICEChannel
|
||||
{
|
||||
std::string name;
|
||||
std::vector<uint32_t> market_types;
|
||||
std::vector<uint32_t> uds_market_types;
|
||||
std::set<UserSymbol> symbols;
|
||||
std::string to_string() const;
|
||||
};
|
||||
|
||||
@@ -151,6 +151,7 @@ message TradeMessage {
|
||||
uint32 total_volume = 7;
|
||||
bool gap = 8;
|
||||
AggressorSide aggressor_side = 9;
|
||||
bool from_spread = 10;
|
||||
}
|
||||
message QuoteRequestMessage {
|
||||
enum Side {
|
||||
|
||||
@@ -219,8 +219,12 @@ public:
|
||||
}
|
||||
|
||||
// the hot part
|
||||
void fill(const SecurityChannel& chan, MDConsumerGroup& group, ChannelReply* reply, bool entitled) const {
|
||||
void fill(const SecurityChannel& chan, MDConsumerGroup& group, ChannelReply* reply,
|
||||
const Entitlements* entitlements, bool bypass_entitlement) const {
|
||||
bts_assert(reply);
|
||||
bool entitled = bypass_entitlement || chan.exchange() == api::VENUE_BTS ||
|
||||
(chan.exchange() == api::VENUE_GLBX && entitlements && entitlements->count(chan.symbol()));
|
||||
|
||||
reply->mutable_channel()->CopyFrom(chan);
|
||||
reply->set_platform(group.platform);
|
||||
reply->mutable_channel()->set_time(TimeStamp::now().to_uint64());
|
||||
@@ -242,9 +246,17 @@ public:
|
||||
ChannelUpdate* pupd = &temp_update;
|
||||
pupd->set_key(instrument.handle.key());
|
||||
// If the security was just discovered try to ensure all data is sent
|
||||
if (instrument.discovered > TimeStamp(chan.time())) {
|
||||
pupd->mutable_security()->CopyFrom(handle.get_normalized_security());
|
||||
if (instrument.discovered > TimeStamp(chan.time()))
|
||||
{
|
||||
auto security = handle.get_normalized_security();
|
||||
pupd->mutable_security()->CopyFrom(security);
|
||||
snapshot = true;
|
||||
if(!entitled && (chan.exchange() == api::VENUE_ICE || chan.exchange() == api::VENUE_SIMICE))
|
||||
{
|
||||
entitled = entitlements && entitlements->count("ICE:" + security.ice().mic_code());
|
||||
if(entitled)
|
||||
reply->mutable_channel()->set_entitled(entitled);
|
||||
}
|
||||
}
|
||||
//if we are not entitled AND this is the first request since we lost our entitlement, zero out books
|
||||
if (!entitled && chan.entitled() ) {
|
||||
@@ -323,12 +335,13 @@ public:
|
||||
TimeStamp time(snapshot ? 0 : chan.time());
|
||||
PriceSize price;
|
||||
datetime::LLDateTime trade_time;
|
||||
size_t volume;
|
||||
if (handle.get_last_trade(time, price, trade_time, &volume)) {
|
||||
size_t volume; int from_spread;
|
||||
if (handle.get_last_trade(time, price, trade_time, &volume, &from_spread)) {
|
||||
auto* trade = pupd->mutable_last_trade();
|
||||
trade->set_key(handle.key());
|
||||
trade->set_time(trade_time);
|
||||
trade->set_total_volume(volume);
|
||||
trade->set_from_spread(from_spread);
|
||||
set_price(price, trade);
|
||||
}
|
||||
}
|
||||
@@ -373,10 +386,7 @@ public:
|
||||
auto groupiter = _groups.find(UserSymbol(ch.symbol(), ch.exchange(), ch.type()));
|
||||
if (groupiter != _groups.end()) {
|
||||
auto& group = groupiter->second;
|
||||
bool is_entitled = bypass_entitlement ||
|
||||
ch.exchange() == api::VENUE_BTS ||
|
||||
(entitlements && entitlements->count(ch.symbol()));
|
||||
fill(ch, *group, reply->add_channels(), is_entitled);
|
||||
fill(ch, *group, reply->add_channels(), entitlements, bypass_entitlement);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -541,10 +551,14 @@ QueryServerPtr run_query_server(const bts::api::ServiceContext& ctx, MDClient& c
|
||||
{
|
||||
const auto& cme_symb_mics = config::get<config::CmeSymbolMics>().cme_mic();
|
||||
auto entitlements = std::make_shared<std::unordered_map<uint32_t, Entitlements>>();
|
||||
for (const auto& row : all_updates) {
|
||||
if (row && row->enabled()) {
|
||||
for(auto mic=cme_symb_mics.begin();mic!=cme_symb_mics.end();mic++){
|
||||
if(api::CMEMics_Name(mic->second) == row->mic()) {
|
||||
for (const auto& row : all_updates)
|
||||
{
|
||||
if (row && row->enabled())
|
||||
{
|
||||
for(auto mic=cme_symb_mics.begin();mic!=cme_symb_mics.end();mic++)
|
||||
{
|
||||
if(api::CMEMics_Name(mic->second) == row->mic())
|
||||
{
|
||||
const auto& symbol = mic->first;
|
||||
auto iter = entitlements->find(row->user_id());
|
||||
if (iter == entitlements->end()) {
|
||||
@@ -559,6 +573,19 @@ QueryServerPtr run_query_server(const bts::api::ServiceContext& ctx, MDClient& c
|
||||
}
|
||||
}
|
||||
}
|
||||
api::ICEMics icemic;
|
||||
if(api::ICEMics_Parse(row->mic(), &icemic)) //this is an ice mic, just put the mic in the set and resolve later
|
||||
{
|
||||
auto iter = entitlements->find(row->user_id());
|
||||
if (iter == entitlements->end()) {
|
||||
Entitlements ents;
|
||||
ents.insert("ICE:" + row->mic());
|
||||
entitlements->insert(iter, std::make_pair(row->user_id(), std::move(ents)));
|
||||
}
|
||||
else {
|
||||
iter->second.insert("ICE:" + row->mic());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
container->relay.update_entitlements(entitlements);
|
||||
|
||||
@@ -86,7 +86,7 @@ class RelayProducer : public IRelayWriter {
|
||||
handle.update_fixing_price(updated, misc.fixing_price());
|
||||
}
|
||||
if (update.has_last_trade()) {
|
||||
handle.set_last_trade(updated, trade_pricesize(update.last_trade()), update.last_trade().time(), update.last_trade().total_volume());
|
||||
handle.set_last_trade(updated, trade_pricesize(update.last_trade()), update.last_trade().time(), update.last_trade().total_volume(), update.last_trade().from_spread());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,8 @@ extern "C" BTS_EXPORT void co2_get_sample_cold(size_t& size, ColdEntry& entry) {
|
||||
entry.misc.session_high_bid = 4.4;
|
||||
entry.misc.session_low_offer = 5.5;
|
||||
entry.misc.fixing_price = 6.6;
|
||||
entry.deleted = true;
|
||||
entry.deleted = 1;
|
||||
entry.from_spread = 0;
|
||||
}
|
||||
|
||||
extern "C" BTS_EXPORT void co2_get_sample_cold_header(ColdHeader& header) {
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/config/protos/jetfix.pb.h"
|
||||
#include "lib/jetfix/codec/MessageDefinitions.h"
|
||||
#include "lib/jetfix/common/OutFIXPtr.h"
|
||||
#include "lib/mercury/events/Update.h"
|
||||
#include "lib/orderman/orderman_utils/orderman_common.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace bts {
|
||||
namespace md { class SecurityOracle;}
|
||||
namespace trace {struct CorID;class PerfLog;}
|
||||
namespace orderman {
|
||||
class NewSecuritiesEvent;
|
||||
class ExecutionReport;
|
||||
|
||||
using OnExeReport =
|
||||
std::function<void(ExecutionReport const &, trace::CorID const &)>;
|
||||
using OnGwStatusChange = std::function<void(bool)>;
|
||||
using OnCancelReject = std::function<void(OrderKey, std::string const &)>;
|
||||
|
||||
// fix execution gateway for a single FIX session
|
||||
class ExecutionGateway {
|
||||
public:
|
||||
ExecutionGateway(config::JetFIX::Connection const &, trace::PerfLog &,
|
||||
md::SecurityOracle);
|
||||
~ExecutionGateway();
|
||||
|
||||
void start();
|
||||
void dispatch_incoming_fix_messages();
|
||||
void on_securities(const mercury::Update<NewSecuritiesEvent> &);
|
||||
void send_fix(jetfix::OutFIXPtr const &fix, trace::CorID trace);
|
||||
|
||||
OnExeReport& on_exe_report();
|
||||
OnGwStatusChange& on_gw_status_change();
|
||||
OnCancelReject &on_cancel_reject();
|
||||
|
||||
private:
|
||||
enum class State { WAITING_FOR_SECURITIES, READY };
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
|
||||
// fix gateway events
|
||||
void on_exe_report(jetfix::fix::ExecutionReportMsg const &);
|
||||
void on_cancel_reject(jetfix::fix::CancelRejectMsg const &);
|
||||
void on_connection_status_change(bool connected);
|
||||
void on_business_reject(jetfix::fix::BusinessMessageRejectMsg const &);
|
||||
void on_session_reject(jetfix::fix::RejectMsg const &);
|
||||
};
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -95,12 +95,13 @@ void FillStore::on_execution_report(
|
||||
if (u.events) {
|
||||
for (auto const &ev : *u.events) {
|
||||
auto &er = *ev.data;
|
||||
auto fk = fmt::format("{}:{}", er.order_key.value(),
|
||||
to_str(er.exchange_fill_id));
|
||||
auto is_known = me->known_fills.count(fk);
|
||||
if (er.exec_type == api::orderman::EXEC_TYPE_PARTIAL_FILL ||
|
||||
er.exec_type == api::orderman::EXEC_TYPE_FILL) {
|
||||
|
||||
auto fk = fmt::format("{}:{}", er.order_key.value(),
|
||||
to_str(er.exchange_fill_id));
|
||||
auto is_known = me->known_fills.count(fk);
|
||||
er.exec_type == api::orderman::EXEC_TYPE_FILL ||
|
||||
er.exec_type == api::orderman::EXEC_TYPE_TRADE_CORRECT) {
|
||||
|
||||
api::orderman::Fill fill;
|
||||
if (!is_known) {
|
||||
fill.set_order_key(er.order_key.value());
|
||||
@@ -116,6 +117,9 @@ void FillStore::on_execution_report(
|
||||
fill.set_avg_price(er.avg_price.value());
|
||||
fill.set_side(er.side);
|
||||
fill.set_last_shares(er.last_shares.value());
|
||||
fill.set_fill_status(api::orderman::Fill::FILL_STATUS_ACTIVE);
|
||||
if(er.exec_type == api::orderman::EXEC_TYPE_TRADE_CORRECT)
|
||||
fill.set_fill_status(api::orderman::Fill::FILL_STATUS_CORRECTED);
|
||||
fill.set_fill_key(fk);
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
@@ -139,6 +143,57 @@ void FillStore::on_execution_report(
|
||||
"Discarding known execution report for fill {}", fk);
|
||||
|
||||
} // if partial_fill or fill
|
||||
}
|
||||
for (auto const &ev : *u.events)
|
||||
{
|
||||
auto &er = *ev.data;
|
||||
auto efi = to_str(er.exchange_fill_id);
|
||||
if(std::count(efi.begin(), efi.end(), ':') > 0)
|
||||
{
|
||||
auto cpos = efi.find_last_of(':');
|
||||
efi = efi.substr(0, cpos);
|
||||
ExchangeFillID temp;
|
||||
str_to(efi, &temp);
|
||||
efi = to_str(temp);
|
||||
}
|
||||
if(efi == "")
|
||||
continue;
|
||||
auto fk = fmt::format("{}:{}", er.order_key.value(), efi);
|
||||
auto is_known = me->known_fills.count(fk);
|
||||
|
||||
if(er.exec_type == api::orderman::EXEC_TYPE_TRADE_CANCEL)
|
||||
{
|
||||
auto data = me->store->retrieve_one(fills_ns, fk);
|
||||
Fill existing_fill;
|
||||
if(is_known && data.first && utils::pb::from_string(data.second, &existing_fill))
|
||||
{
|
||||
existing_fill.set_fill_status(api::orderman::Fill::FILL_STATUS_BUSTED);
|
||||
auto fv = utils::pb::to_string(existing_fill);
|
||||
me->store->update(fills_ns, fk, fv);
|
||||
publish(me->fill_stream, existing_fill, *er.security);
|
||||
}
|
||||
else
|
||||
LOG(OrderMan, Warn, "Received bust for unknown fill {}", fk);
|
||||
}
|
||||
else if(er.exec_type == api::orderman::EXEC_TYPE_TRADE_CORRECT)
|
||||
{
|
||||
auto data = me->store->retrieve_one(fills_ns, fk);
|
||||
Fill existing_fill;
|
||||
if(is_known && data.first && utils::pb::from_string(data.second, &existing_fill))
|
||||
{
|
||||
existing_fill.set_fill_status(api::orderman::Fill::FILL_STATUS_CORRECTED);
|
||||
existing_fill.set_last_price(er.last_price.value());
|
||||
existing_fill.set_avg_price(er.avg_price.value());
|
||||
existing_fill.set_side(er.side);
|
||||
existing_fill.set_last_shares(er.last_shares.value());
|
||||
|
||||
auto fv = utils::pb::to_string(existing_fill);
|
||||
me->store->update(fills_ns, fk, fv);
|
||||
publish(me->fill_stream, existing_fill, *er.security);
|
||||
}
|
||||
else
|
||||
LOG(OrderMan, Warn, "Received correction for unknown fill {}", fk);
|
||||
}
|
||||
} // for loop
|
||||
} // if u.events
|
||||
}
|
||||
|
||||
+20
-18
@@ -1,4 +1,4 @@
|
||||
#include "ExecutionGateway.h"
|
||||
#include "GLBXExecutionGateway.h"
|
||||
#include "lib/jetfix/codec/MessageDefinitions.h"
|
||||
#include "lib/jetfix/common/OutFIX.h"
|
||||
#include "lib/jetfix/gateway/JetFIXGateway.h"
|
||||
@@ -24,7 +24,7 @@ using JFGw =
|
||||
JetFIXGateway<fix::ExecutionReportMsg, fix::BusinessMessageRejectMsg,
|
||||
fix::RejectMsg, fix::CancelRejectMsg>;
|
||||
|
||||
struct ExecutionGateway::PImpl {
|
||||
struct GLBXExecutionGateway::PImpl {
|
||||
PImpl(config::JetFIX::Connection const &cfg, trace::PerfLog &l,
|
||||
md::SecurityOracle o)
|
||||
: gw(cfg, l), exe_report_pool(), state(State::WAITING_FOR_SECURITIES),
|
||||
@@ -46,14 +46,16 @@ struct ExecutionGateway::PImpl {
|
||||
md::SecurityOracle sec_oracle;
|
||||
};
|
||||
|
||||
ExecutionGateway::ExecutionGateway(config::JetFIX::Connection const &cfg,
|
||||
GLBXExecutionGateway::GLBXExecutionGateway(config::JetFIX::Connection const &cfg,
|
||||
trace::PerfLog &log, md::SecurityOracle o)
|
||||
: me(new PImpl(cfg, log, o)) {
|
||||
me->state = State::WAITING_FOR_SECURITIES;
|
||||
}
|
||||
ExecutionGateway::~ExecutionGateway() {}
|
||||
GLBXExecutionGateway::~GLBXExecutionGateway() {}
|
||||
|
||||
void ExecutionGateway::on_securities(
|
||||
void GLBXExecutionGateway::on_admin_data(const mercury::Update<NewAdminDataEvent> &) {}
|
||||
|
||||
void GLBXExecutionGateway::on_securities(
|
||||
const mercury::Update<NewSecuritiesEvent> &update) {
|
||||
if (update.events) {
|
||||
|
||||
@@ -96,19 +98,19 @@ void ExecutionGateway::on_securities(
|
||||
}
|
||||
}
|
||||
|
||||
void ExecutionGateway::start() { me->gw.start(); }
|
||||
void GLBXExecutionGateway::start() { me->gw.start(); }
|
||||
|
||||
OnExeReport &ExecutionGateway::on_exe_report() { return me->on_exe_report; }
|
||||
OnExeReport &GLBXExecutionGateway::on_exe_report() { return me->on_exe_report; }
|
||||
|
||||
OnGwStatusChange &ExecutionGateway::on_gw_status_change() {
|
||||
OnGwStatusChange &GLBXExecutionGateway::on_gw_status_change() {
|
||||
return me->on_gw_status_change;
|
||||
}
|
||||
|
||||
OnCancelReject &ExecutionGateway::on_cancel_reject() {
|
||||
OnCancelReject &GLBXExecutionGateway::on_cancel_reject() {
|
||||
return me->on_cancel_reject;
|
||||
}
|
||||
|
||||
void ExecutionGateway::on_exe_report(
|
||||
void GLBXExecutionGateway::on_exe_report(
|
||||
const jetfix::fix::ExecutionReportMsg &msg) {
|
||||
OrderKey ok;
|
||||
SecurityKey sk;
|
||||
@@ -116,7 +118,7 @@ void ExecutionGateway::on_exe_report(
|
||||
|
||||
auto scoped_log =
|
||||
trace::log_scope(me->perf_log, msg.trace(),
|
||||
"ExecutionGateway::on_exe_report", ok.value());
|
||||
"GLBXExecutionGateway::on_exe_report", ok.value());
|
||||
|
||||
LOG(Latency, Info, "Started handling of execution report for order {}",
|
||||
ok.value());
|
||||
@@ -266,7 +268,7 @@ void ExecutionGateway::on_exe_report(
|
||||
}
|
||||
}
|
||||
|
||||
void ExecutionGateway::on_cancel_reject(
|
||||
void GLBXExecutionGateway::on_cancel_reject(
|
||||
const jetfix::fix::CancelRejectMsg &msg) {
|
||||
OrderKey ok;
|
||||
SecurityKey sk;
|
||||
@@ -281,7 +283,7 @@ void ExecutionGateway::on_cancel_reject(
|
||||
me->on_cancel_reject(ok, reject_msg);
|
||||
}
|
||||
|
||||
void ExecutionGateway::on_connection_status_change(bool is_connected) {
|
||||
void GLBXExecutionGateway::on_connection_status_change(bool is_connected) {
|
||||
LOG(OrderMan, Info, "Connection state of {} changed to {}",
|
||||
me->gw_name.value(),
|
||||
is_connected ? std::string("connected") : std::string("disconnected"));
|
||||
@@ -289,7 +291,7 @@ void ExecutionGateway::on_connection_status_change(bool is_connected) {
|
||||
me->on_gw_status_change(is_connected);
|
||||
}
|
||||
|
||||
void ExecutionGateway::on_business_reject(
|
||||
void GLBXExecutionGateway::on_business_reject(
|
||||
jetfix::fix::BusinessMessageRejectMsg const &m) {
|
||||
LOG(OrderMan, Error,
|
||||
"Unexpected business reject in {} gateway . Reason: "
|
||||
@@ -298,7 +300,7 @@ void ExecutionGateway::on_business_reject(
|
||||
m.has<fix::Text>() ? m.get<fix::Text>() : std::string("Unknown"));
|
||||
}
|
||||
|
||||
void ExecutionGateway::on_session_reject(jetfix::fix::RejectMsg const &m) {
|
||||
void GLBXExecutionGateway::on_session_reject(jetfix::fix::RejectMsg const &m) {
|
||||
LOG(OrderMan, Error,
|
||||
"Unexpected reject message in {} gateway . Reason: {}. "
|
||||
"This should be investigated",
|
||||
@@ -306,14 +308,14 @@ void ExecutionGateway::on_session_reject(jetfix::fix::RejectMsg const &m) {
|
||||
m.has<fix::Text>() ? m.get<fix::Text>() : std::string("Unknown"));
|
||||
}
|
||||
|
||||
void ExecutionGateway::dispatch_incoming_fix_messages() {
|
||||
void GLBXExecutionGateway::dispatch_incoming_fix_messages() {
|
||||
me->gw.dispatch_events();
|
||||
}
|
||||
|
||||
void ExecutionGateway::send_fix(jetfix::OutFIXPtr const &fix,
|
||||
void GLBXExecutionGateway::send_fix(jetfix::OutFIXPtr const &fix,
|
||||
trace::CorID trace) {
|
||||
auto scoped_log =
|
||||
trace::log_scope(me->perf_log, trace, "ExecutionGateway::send_fix");
|
||||
trace::log_scope(me->perf_log, trace, "GLBXExecutionGateway::send_fix");
|
||||
me->gw.send(fix, trace);
|
||||
me->gw.dispatch_events();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "IExecutionGateway.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
|
||||
// fix execution gateway for a single FIX session
|
||||
class GLBXExecutionGateway : public IExecutionGateway {
|
||||
public:
|
||||
GLBXExecutionGateway(config::JetFIX::Connection const &, trace::PerfLog &,
|
||||
md::SecurityOracle);
|
||||
virtual ~GLBXExecutionGateway();
|
||||
|
||||
void start() override;
|
||||
void dispatch_incoming_fix_messages() override;
|
||||
void on_securities(const mercury::Update<NewSecuritiesEvent> &) override;
|
||||
void on_admin_data(const mercury::Update<NewAdminDataEvent> &) override;
|
||||
void send_fix(jetfix::OutFIXPtr const &fix, trace::CorID trace) override;
|
||||
|
||||
OnExeReport& on_exe_report() override;
|
||||
OnGwStatusChange& on_gw_status_change() override;
|
||||
OnCancelReject &on_cancel_reject() override;
|
||||
|
||||
private:
|
||||
BTS_NO_COPY(GLBXExecutionGateway);
|
||||
enum class State { WAITING_FOR_SECURITIES, READY };
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
|
||||
// fix gateway events
|
||||
void on_exe_report(jetfix::fix::ExecutionReportMsg const &);
|
||||
void on_cancel_reject(jetfix::fix::CancelRejectMsg const &);
|
||||
void on_connection_status_change(bool connected);
|
||||
void on_business_reject(jetfix::fix::BusinessMessageRejectMsg const &);
|
||||
void on_session_reject(jetfix::fix::RejectMsg const &);
|
||||
};
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,490 @@
|
||||
#include "ICEExecutionGateway.h"
|
||||
#include "lib/jetfix/codec/MessageDefinitions.h"
|
||||
#include "lib/jetfix/codec/i32_toa.h"
|
||||
#include "lib/jetfix/common/OutFIX.h"
|
||||
#include "lib/jetfix/gateway/JetFIXGateway.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/orderman/events/CancelRejectEvent.h"
|
||||
#include "lib/orderman/events/GatewayStatusChangeEvent.h"
|
||||
#include "lib/orderman/events/NewExecutionReportEvent.h"
|
||||
#include "lib/orderman/events/NewSecuritiesEvent.h"
|
||||
#include "lib/orderman/orderman_utils/fix_order_codec.h"
|
||||
#include "lib/api/services/AdminService.pb.h"
|
||||
#include "lib/orderman/events/NewAdminDataEvent.h"
|
||||
#include "lib/tracing/bts_trace.h"
|
||||
#include "lib/utils/TimeStamp.h"
|
||||
#include "lib/utils/helper_macros.h"
|
||||
#include "lib/utils/Dispatcher.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
|
||||
#include <boost/pool/object_pool.hpp>
|
||||
#include <atomic>
|
||||
#include <set>
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
using namespace jetfix;
|
||||
|
||||
using JFGw = JetFIXGateway<fix::ICEExecutionReportMsg, fix::BusinessMessageRejectMsg, fix::RejectMsg,
|
||||
fix::ICECancelRejectMsg, fix::ICETraderLoginResponseMsg, fix::ICETraderLogoutResponseMsg>;
|
||||
|
||||
|
||||
|
||||
struct ICEExecutionGateway::PImpl
|
||||
{
|
||||
PImpl(const config::JetFIX::Connection &cfg, trace::PerfLog &l,
|
||||
md::SecurityOracle o)
|
||||
: gw(cfg, l), exe_report_pool(), state(State::WAITING_FOR_SECURITIES),
|
||||
securities(), securities_by_exchange_id(), gw_name(cfg.name()),
|
||||
cfg(cfg), perf_log(l), admin_data(), nusers(-1), connection_time(), exec_id_to_memo(),
|
||||
sec_oracle(o)
|
||||
{}
|
||||
|
||||
JFGw gw;
|
||||
boost::object_pool<ExecutionReport> exe_report_pool;
|
||||
State state;
|
||||
std::unordered_map<SecurityKey::Value, api::Security const *> securities;
|
||||
std::unordered_map<int64_t, api::Security const *> securities_by_exchange_id;
|
||||
GatewayName gw_name;
|
||||
config::JetFIX::Connection cfg;
|
||||
OnExeReport on_exe_report;
|
||||
OnGwStatusChange on_gw_status_change;
|
||||
OnCancelReject on_cancel_reject;
|
||||
trace::PerfLog &perf_log;
|
||||
api::admin::AdminData admin_data;
|
||||
std::atomic<int> nusers;
|
||||
TimeStamp connection_time;
|
||||
std::unordered_map<std::string, std::string> exec_id_to_memo; //for the bullshit adjusts
|
||||
md::SecurityOracle sec_oracle;
|
||||
};
|
||||
|
||||
ICEExecutionGateway::ICEExecutionGateway(const config::JetFIX::Connection &cfg, trace::PerfLog &log, md::SecurityOracle o)
|
||||
: IExecutionGateway(), me(new PImpl(cfg, log, o))
|
||||
{
|
||||
me->state = State::WAITING_FOR_ADMIN;
|
||||
}
|
||||
|
||||
ICEExecutionGateway::~ICEExecutionGateway() {}
|
||||
|
||||
void ICEExecutionGateway::on_admin_data(const mercury::Update<NewAdminDataEvent>& update)
|
||||
{
|
||||
if (update.events)
|
||||
{
|
||||
for (auto const &ev : *(update.events))
|
||||
me->admin_data.CopyFrom(*ev.admin_data);
|
||||
|
||||
if (me->state == State::WAITING_FOR_ADMIN)
|
||||
{
|
||||
LOG(OrderMan, Warn, "Received admin data. Waiting for securities {}", me->gw_name.value());
|
||||
me->state = State::WAITING_FOR_SECURITIES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ICEExecutionGateway::on_securities(const mercury::Update<NewSecuritiesEvent> &update)
|
||||
{
|
||||
if (update.events)
|
||||
{
|
||||
for (auto const &ev : *(update.events))
|
||||
{
|
||||
auto sec_ptr = ev.security;
|
||||
me->securities[sec_ptr->id()] = sec_ptr;
|
||||
if(sec_ptr->has_ice())
|
||||
me->securities_by_exchange_id[sec_ptr->ice().exchange_id()] = sec_ptr;
|
||||
}
|
||||
|
||||
if (me->state == State::WAITING_FOR_SECURITIES)
|
||||
{
|
||||
LOG(OrderMan, Warn, "Received first set of {} securities. Beginning wait 2s for trader login {}",
|
||||
update.events->size(), me->gw_name.value());
|
||||
// got our security synopsis, ready to start the GW
|
||||
me->state = State::READY_TO_START_GW;
|
||||
|
||||
// subscribe to gateway events
|
||||
me->gw.on<fix::ICEExecutionReportMsg>() = [this](auto const &msg)
|
||||
{
|
||||
this->on_exe_report(msg);
|
||||
};
|
||||
me->gw.on<fix::ICECancelRejectMsg>() = [this](auto const &msg)
|
||||
{
|
||||
this->on_cancel_reject(msg);
|
||||
};
|
||||
me->gw.on_ready() = [this]()
|
||||
{
|
||||
this->on_connection_status_change(true);
|
||||
};
|
||||
me->gw.on_disconnect() = [this]()
|
||||
{
|
||||
this->on_connection_status_change(false);
|
||||
};
|
||||
me->gw.on<fix::BusinessMessageRejectMsg>() = [this](auto const &m)
|
||||
{
|
||||
this->on_business_reject(m);
|
||||
};
|
||||
me->gw.on<fix::RejectMsg>() = [this](auto const &m)
|
||||
{
|
||||
this->on_session_reject(m);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ICEExecutionGateway::start()
|
||||
{
|
||||
me->gw.start();
|
||||
bts_assert_msg(me->state == State::READY_TO_START_GW, "ICEExecutionGateway statemachine failure");
|
||||
}
|
||||
|
||||
void ICEExecutionGateway::on_connection_status_change(bool is_connected)
|
||||
{
|
||||
LOG(OrderMan, Info, "Connection state of {} changed to {}",
|
||||
me->gw_name.value(), is_connected ? std::string("connected") : std::string("disconnected"));
|
||||
|
||||
if(is_connected && me->state == State::READY_TO_START_GW)
|
||||
{
|
||||
me->state = State::TRADER_LOGIN_TIMEOUT;
|
||||
me->connection_time = Timer::now();
|
||||
}
|
||||
|
||||
if(me->state == State::READY)
|
||||
{
|
||||
me->on_gw_status_change(is_connected);
|
||||
if(!is_connected) //if we disconnect, set state so we log in again
|
||||
me->state = State::READY_TO_START_GW;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ICEExecutionGateway::on_trader_login_timeout_expired()
|
||||
{
|
||||
if (me->state == State::TRADER_LOGIN_TIMEOUT)
|
||||
{
|
||||
LOG(OrderMan, Warn, "Done waiting for login timeout, logging on traders {}", me->gw_name.value());
|
||||
|
||||
// got our security synopsis, ready to start the GW
|
||||
me->state = State::LOGIN_TIMEOUT_COMPLETE;
|
||||
me->gw.on<fix::ICETraderLoginResponseMsg>() = [&](const fix::ICETraderLoginResponseMsg& lmsg)
|
||||
{
|
||||
std::string u = lmsg.get<fix::UserName>();
|
||||
std::string m;
|
||||
if(lmsg.has<fix::Text>())
|
||||
m = lmsg.get<fix::Text>();
|
||||
LOG(OrderMan, Error, "Succesffully logging trader {} into ICE {} {}", u, m, me->gw_name.value());
|
||||
if(--me->nusers == 0)
|
||||
this->on_login();
|
||||
};
|
||||
|
||||
me->gw.on<fix::ICETraderLogoutResponseMsg>() = [&](const fix::ICETraderLogoutResponseMsg& lmsg)
|
||||
{
|
||||
std::string u = lmsg.get<fix::UserName>();
|
||||
std::string m;
|
||||
if(lmsg.has<fix::Text>())
|
||||
m = lmsg.get<fix::Text>();
|
||||
|
||||
LOG(OrderMan, Error, "Error logging trader {} into ICE {} {}", u, m, me->gw_name.value());
|
||||
if(--me->nusers == 0)
|
||||
this->on_login();
|
||||
};
|
||||
|
||||
std::set<std::string> auth_traders;
|
||||
for(const auto& u : me->admin_data.users())
|
||||
{
|
||||
if(u.has_user_data() && u.user_data().has_exchange_user_data() && u.user_data().exchange_user_data().has_ice_data())
|
||||
{
|
||||
const auto& ice = u.user_data().exchange_user_data().ice_data();
|
||||
if(auth_traders.find(ice.authorized_trader()) == auth_traders.end())
|
||||
{
|
||||
if(me->nusers == -1)
|
||||
me->nusers = 0;
|
||||
me->nusers++;
|
||||
|
||||
auto result = std::make_shared<OutFIX>(me->cfg);
|
||||
auto &stream = result->fix.back();
|
||||
auto &buffer = stream.new_msg(MessageTypes::ICETraderLogin);
|
||||
buffer.add<fix::CompanyID>(ice.company_id());
|
||||
buffer.add<fix::UserName>(ice.authorized_trader());
|
||||
buffer.add<fix::RawData>(ice.password());
|
||||
|
||||
if(ice.mifid_direct_electronic_access() >= 0)
|
||||
buffer.add<fix::MifidDirectElectronicAccess>(ice.mifid_direct_electronic_access());
|
||||
if(ice.mifid_trading_capacity() >= 0)
|
||||
buffer.add<fix::MifidTradingCapacity>(ice.mifid_trading_capacity());
|
||||
if(ice.mifid_liquidity_provision() >= 0)
|
||||
buffer.add<fix::MifidLiquidityProvision>(ice.mifid_liquidity_provision());
|
||||
if(ice.mifid_commodity_deriv_indicator() >= 0)
|
||||
buffer.add<fix::MifidCommodityDerivIndicator>(ice.mifid_commodity_deriv_indicator());
|
||||
if(ice.mifid_investment_decision() > 0)
|
||||
buffer.add<fix::MifidInvestmentDecision>(ice.mifid_investment_decision());
|
||||
if(ice.mifid_execution_decision() > 0)
|
||||
buffer.add<fix::MifidExecutionDecision>(ice.mifid_execution_decision());
|
||||
if(ice.mifid_client_id_code() > 0)
|
||||
buffer.add<fix::MifidClientIDCode>(ice.mifid_client_id_code());
|
||||
if(ice.mifid_id() > 0)
|
||||
buffer.add<fix::MifidId>(ice.mifid_id());
|
||||
stream.close();
|
||||
|
||||
trace::CorID trace;
|
||||
send_fix(result, trace);
|
||||
auth_traders.insert(ice.authorized_trader());
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG(OrderMan, Warn, "{} traders identified as ICE traders {}", auth_traders.size(), me->gw_name.value());
|
||||
}
|
||||
}
|
||||
|
||||
void ICEExecutionGateway::on_login()
|
||||
{
|
||||
if (me->state == State::LOGIN_TIMEOUT_COMPLETE)
|
||||
{
|
||||
LOG(OrderMan, Warn, "Successful login traders {}", me->gw_name.value());
|
||||
me->state = State::READY;
|
||||
me->on_gw_status_change(true);
|
||||
}
|
||||
}
|
||||
|
||||
OnExeReport &ICEExecutionGateway::on_exe_report() { return me->on_exe_report; }
|
||||
|
||||
OnGwStatusChange &ICEExecutionGateway::on_gw_status_change()
|
||||
{
|
||||
return me->on_gw_status_change;
|
||||
}
|
||||
|
||||
OnCancelReject &ICEExecutionGateway::on_cancel_reject()
|
||||
{
|
||||
return me->on_cancel_reject;
|
||||
}
|
||||
|
||||
bool ICEExecutionGateway::process_memo(const jetfix::fix::ICEExecutionReportMsg &msg, OrderKey* ok, SecurityKey* sk)
|
||||
{
|
||||
if(msg.has<fix::Memo>())
|
||||
{
|
||||
decode_memo(msg.get<fix::Memo>(), ok, sk);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (msg.get<fix::ExecType>() == api::orderman::EXEC_TYPE_TRADE_CORRECT && msg.has<fix::ExecRefID>())
|
||||
{
|
||||
std::string ref_exec_id = msg.get<fix::ExecRefID>();
|
||||
auto found = me->exec_id_to_memo.find(ref_exec_id);
|
||||
if(found == me->exec_id_to_memo.end())
|
||||
{
|
||||
auto new_price = Price(0);
|
||||
if(msg.has<fix::LastPx>())
|
||||
new_price = Price(msg.get<fix::LastPx>());
|
||||
|
||||
LOG(OrderMan, Error,
|
||||
"Received unsupported trade correction msg. This correction will not be forwarded. The trader should be alerted. "
|
||||
"Partial original fill id: {}. New price: {}", ref_exec_id, new_price.value());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
decode_memo(found->second, ok, sk);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ICEExecutionGateway::on_exe_report(const jetfix::fix::ICEExecutionReportMsg &msg)
|
||||
{
|
||||
OrderKey ok;
|
||||
SecurityKey sk;
|
||||
if(!process_memo(msg, &ok, &sk))
|
||||
{
|
||||
std::string execid = "";
|
||||
if(msg.has<fix::ExecID>())
|
||||
execid = msg.get<fix::ExecID>();
|
||||
LOG(OrderMan, Error,
|
||||
"Received execution report with no memo execid: {}. Will not be able to process this report. This is likely a bug that could lead "
|
||||
"to lost fills. Please investigate.", execid);
|
||||
return;
|
||||
}
|
||||
auto scoped_log = trace::log_scope(me->perf_log, msg.trace(), "ICEExecutionGateway::on_exe_report", ok.value());
|
||||
|
||||
LOG(Latency, Info, "Started handling of execution report for order {}", ok.value());
|
||||
auto &sec = me->securities[sk.value()];
|
||||
if (!sec)
|
||||
{
|
||||
sec = me->sec_oracle.get_security(SecurityKey(sk.value()));
|
||||
}
|
||||
if (!sec)
|
||||
LOG(OrderMan, Error,
|
||||
"Received execution report for an unknown security {}. Will not be able to process this report. This is likely a bug that could lead "
|
||||
"to lost fills. Please investigate.",
|
||||
sk.value());
|
||||
else
|
||||
{
|
||||
if(sec->has_ice())
|
||||
me->securities_by_exchange_id[sec->ice().exchange_id()] = sec;
|
||||
|
||||
api::Security const *leg_security = nullptr;
|
||||
if (msg.has<fix::MultiLegReportingType>() && msg.get<fix::MultiLegReportingType>() == 2)
|
||||
{
|
||||
auto it = me->securities_by_exchange_id.find(msg.get<fix::Int_Symbol>());
|
||||
if (it == me->securities_by_exchange_id.end())
|
||||
{
|
||||
LOG(OrderMan, Error,
|
||||
"Received execution report for an unknown spread leg"
|
||||
"security {}. Will not be able to process this report. "
|
||||
"This is likely a bug that could lead to "
|
||||
"lost leg fills. Please investigate. Spread sec_key: {} leg "
|
||||
"exchange id: {}",
|
||||
sk.value(), msg.get<fix::Int_Symbol>());
|
||||
return;
|
||||
}
|
||||
leg_security = it->second;
|
||||
}
|
||||
std::string text_msg;
|
||||
if (msg.has<fix::Text>())
|
||||
text_msg = msg.get<fix::Text>();
|
||||
if (msg.has<fix::OrdRejReason>())
|
||||
text_msg += " Rejected OrdRejReason: " + std::to_string(msg.get<fix::OrdRejReason>());
|
||||
|
||||
if (msg.has<fix::DeleteReason>())
|
||||
text_msg += " Cancelled DeleteReason: " + std::to_string(msg.get<fix::DeleteReason>());
|
||||
|
||||
// allocate from our pool
|
||||
auto data = me->exe_report_pool.construct();
|
||||
|
||||
if(msg.has<fix::Memo>())
|
||||
data->memo = msg.get<fix::Memo>();
|
||||
data->exec_type = api::orderman::ExecType(msg.get<fix::ExecType>());
|
||||
data->msg_seq_num = msg.get<fix::MsgSeqNum>();
|
||||
|
||||
// copy data from fix msg to our structure
|
||||
if (msg.has<fix::ClearingAccount>())
|
||||
str_to(msg.get<fix::ClearingAccount>(), &data->account_name);
|
||||
if (msg.has<fix::TargetSubID>())
|
||||
str_to(msg.get<fix::TargetSubID>(), &data->operator_id);
|
||||
if (msg.has<fix::CompanyID>())
|
||||
data->ice_company_id = msg.get<fix::CompanyID>();
|
||||
|
||||
data->order_key = ok;
|
||||
data->security = sec;
|
||||
data->leg_security = leg_security;
|
||||
data->side = api::Side(msg.get<fix::Side>());
|
||||
if (msg.has<fix::TimeInForce>())
|
||||
data->time_in_force = api::orderman::TimeInForce(msg.get<fix::TimeInForce>());
|
||||
else
|
||||
data->time_in_force = api::orderman::TIME_IN_FORCE_UNDEFINED;
|
||||
|
||||
if (msg.has<fix::OrdType>())
|
||||
data->order_type = api::orderman::NativeOrderType(msg.get<fix::OrdType>());
|
||||
else
|
||||
data->order_type = api::orderman::NATIVE_ORDER_TYPE_UNDEFINED;
|
||||
|
||||
data->order_status = api::orderman::NativeOrderStatus(msg.get<fix::OrdStatus>());
|
||||
data->manual_order_indicator = api::orderman::MANUAL_ORDER_INDICATOR_NO;
|
||||
|
||||
std::string oid_string = get_ice_order_id_string(msg);
|
||||
str_to(oid_string, &data->exchange_order_id);
|
||||
data->ice_cl_ord_id = 0;
|
||||
if(msg.has<fix::Int_ClOrdID>())
|
||||
data->ice_cl_ord_id = msg.get<fix::Int_ClOrdID>();
|
||||
|
||||
if (msg.has<fix::Price>())
|
||||
data->price = securities::decode_exchange_price(*sec, Price(msg.get<fix::Price>()));
|
||||
else
|
||||
data->price = Price(os::nan());
|
||||
|
||||
if (msg.has<fix::StopPx>())
|
||||
data->stop_price = securities::decode_exchange_price(*sec, Price(msg.get<fix::StopPx>()));
|
||||
else
|
||||
data->stop_price = Price(os::nan());
|
||||
|
||||
if (msg.has<fix::MaxShow>())
|
||||
data->max_show = Quantity(msg.get<fix::MaxShow>());
|
||||
else
|
||||
data->max_show = Quantity(0);
|
||||
|
||||
if (msg.has<fix::OrderQty>())
|
||||
data->quantity = Quantity(msg.get<fix::OrderQty>());
|
||||
else
|
||||
data->quantity = Quantity(0);
|
||||
|
||||
data->filled_quantity = Quantity(msg.get<fix::CumQty>());
|
||||
|
||||
data->last_shares = msg.has<fix::LastShares>()
|
||||
? Quantity(msg.get<fix::LastShares>())
|
||||
: Quantity(0);
|
||||
auto last_px_sec = data->leg_security ? data->leg_security : sec;
|
||||
data->last_price = msg.has<fix::LastPx>()
|
||||
? securities::decode_exchange_price(*last_px_sec, Price(msg.get<fix::LastPx>()))
|
||||
: Price(0);
|
||||
data->avg_price = msg.has<fix::AvgPx>()
|
||||
? securities::decode_exchange_price(*last_px_sec, Price(msg.get<fix::AvgPx>()))
|
||||
: Price(0);
|
||||
if (msg.has<fix::ExecID>())
|
||||
{
|
||||
auto execid = msg.get<fix::ExecID>();
|
||||
str_to(execid, &data->exchange_fill_id);
|
||||
if(msg.has<fix::Memo>())
|
||||
me->exec_id_to_memo[execid] = msg.get<fix::Memo>();
|
||||
}
|
||||
|
||||
if (msg.has<fix::TransactTimeStr>())
|
||||
{
|
||||
std::string stamp = msg.get<fix::TransactTimeStr>();
|
||||
stamp.resize(sizeof(mercury::TimeStampStr));
|
||||
str_to(stamp, &data->transact_time);
|
||||
}
|
||||
data->cfg = &me->cfg;
|
||||
data->msg = text_msg;
|
||||
data->exchange = api::Venue::VENUE_ICE;
|
||||
me->on_exe_report(*data, msg.trace());
|
||||
}
|
||||
}
|
||||
|
||||
void ICEExecutionGateway::on_cancel_reject(const jetfix::fix::ICECancelRejectMsg &msg)
|
||||
{
|
||||
OrderKey ok(msg.get<fix::Int_ClOrdID>());
|
||||
|
||||
std::string reject_msg;
|
||||
if (msg.has<fix::Text>())
|
||||
reject_msg = msg.get<fix::Text>();
|
||||
else if (msg.has<fix::CXlRejReason>())
|
||||
reject_msg = fmt::format("Order cancel was rejected with error code {}",
|
||||
msg.get<fix::CXlRejReason>());
|
||||
me->on_cancel_reject(ok, reject_msg);
|
||||
}
|
||||
|
||||
|
||||
void ICEExecutionGateway::on_business_reject(const jetfix::fix::BusinessMessageRejectMsg& m)
|
||||
{
|
||||
LOG(OrderMan, Error,
|
||||
"Unexpected business reject in {} gateway . Reason: {}. This should be investigated",
|
||||
me->gw_name.value(),
|
||||
m.has<fix::Text>() ? m.get<fix::Text>() : std::string("Unknown"));
|
||||
}
|
||||
|
||||
void ICEExecutionGateway::on_session_reject(const jetfix::fix::RejectMsg& m)
|
||||
{
|
||||
LOG(OrderMan, Error,
|
||||
"Unexpected reject message in {} gateway . Reason: {}. This should be investigated",
|
||||
me->gw_name.value(),
|
||||
m.has<fix::Text>() ? m.get<fix::Text>() : std::string("Unknown"));
|
||||
}
|
||||
|
||||
void ICEExecutionGateway::dispatch_incoming_fix_messages()
|
||||
{
|
||||
me->gw.dispatch_events();
|
||||
if(me->state == State::TRADER_LOGIN_TIMEOUT && ms_diff(Timer::now(), me->connection_time) >= 2000)
|
||||
{
|
||||
on_trader_login_timeout_expired();
|
||||
}
|
||||
}
|
||||
|
||||
void ICEExecutionGateway::send_fix(const jetfix::OutFIXPtr& fix, trace::CorID trace)
|
||||
{
|
||||
auto scoped_log = trace::log_scope(me->perf_log,trace,"ICEExecutionGateway::send_fix");
|
||||
me->gw.send(fix,trace);
|
||||
me->gw.dispatch_events();
|
||||
}
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "IExecutionGateway.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
// fix execution gateway for a single FIX session
|
||||
class ICEExecutionGateway : public IExecutionGateway {
|
||||
public:
|
||||
ICEExecutionGateway(const config::JetFIX::Connection&, trace::PerfLog &,
|
||||
md::SecurityOracle);
|
||||
virtual ~ICEExecutionGateway();
|
||||
|
||||
void start() override;
|
||||
void dispatch_incoming_fix_messages() override;
|
||||
void on_securities(const mercury::Update<NewSecuritiesEvent> &) override;
|
||||
void on_admin_data(const mercury::Update<NewAdminDataEvent> &) override;
|
||||
void send_fix(const jetfix::OutFIXPtr& fix, trace::CorID trace) override;
|
||||
|
||||
OnExeReport& on_exe_report() override;
|
||||
OnGwStatusChange& on_gw_status_change() override;
|
||||
OnCancelReject &on_cancel_reject() override;
|
||||
|
||||
private:
|
||||
BTS_NO_COPY(ICEExecutionGateway);
|
||||
enum class State { WAITING_FOR_ADMIN, WAITING_FOR_SECURITIES, READY_TO_START_GW, TRADER_LOGIN_TIMEOUT, LOGIN_TIMEOUT_COMPLETE, READY };
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
|
||||
void on_trader_login_timeout_expired();
|
||||
void on_login();
|
||||
|
||||
// fix gateway events
|
||||
void on_exe_report(const jetfix::fix::ICEExecutionReportMsg&);
|
||||
void on_cancel_reject(const jetfix::fix::ICECancelRejectMsg&);
|
||||
void on_connection_status_change(bool connected);
|
||||
void on_business_reject(const jetfix::fix::BusinessMessageRejectMsg&);
|
||||
void on_session_reject(const jetfix::fix::RejectMsg&);
|
||||
|
||||
bool process_memo(const jetfix::fix::ICEExecutionReportMsg &msg, OrderKey*, SecurityKey*);
|
||||
};
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
#include "IExecutionGateway.h"
|
||||
#include "ICEExecutionGateway.h"
|
||||
#include "GLBXExecutionGateway.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
std::unique_ptr<IExecutionGateway>
|
||||
ExecutionGatewayFactory::create_gateway(const config::JetFIX::Connection& conn, trace::PerfLog& pl, md::SecurityOracle o)
|
||||
{
|
||||
if(conn.platform() == bts::config::JetFIX_Connection_JetFIXPlatform_ICE ||
|
||||
conn.platform() == bts::config::JetFIX_Connection_JetFIXPlatform_SIMICE)
|
||||
return std::make_unique<ICEExecutionGateway>(conn, pl, o);
|
||||
else
|
||||
return std::make_unique<GLBXExecutionGateway>(conn, pl, o);
|
||||
}
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/config/protos/jetfix.pb.h"
|
||||
#include "lib/jetfix/codec/MessageDefinitions.h"
|
||||
#include "lib/jetfix/common/OutFIXPtr.h"
|
||||
#include "lib/md/SecurityOracle.h"
|
||||
#include "lib/mercury/events/Update.h"
|
||||
#include "lib/orderman/orderman_utils/orderman_common.h"
|
||||
#include "lib/utils/bts_no_copy.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace bts {
|
||||
namespace trace {struct CorID;class PerfLog;}
|
||||
namespace orderman {
|
||||
class NewSecuritiesEvent;
|
||||
class NewAdminDataEvent;
|
||||
class ExecutionReport;
|
||||
|
||||
|
||||
using OnGwStatusChange = std::function<void(bool)>;
|
||||
using OnExeReport = std::function<void(ExecutionReport const &, trace::CorID const &)>;
|
||||
using OnCancelReject = std::function<void(OrderKey, std::string const &)>;
|
||||
|
||||
// fix execution gateway for a single FIX session
|
||||
class IExecutionGateway {
|
||||
public:
|
||||
IExecutionGateway() = default;
|
||||
virtual ~IExecutionGateway() {}
|
||||
|
||||
virtual void start() = 0;
|
||||
virtual void dispatch_incoming_fix_messages() = 0;
|
||||
virtual void on_securities(const mercury::Update<NewSecuritiesEvent> &) = 0;
|
||||
virtual void on_admin_data(const mercury::Update<NewAdminDataEvent> &) = 0;
|
||||
virtual void send_fix(const jetfix::OutFIXPtr&, trace::CorID) = 0;
|
||||
|
||||
virtual OnExeReport& on_exe_report() = 0;
|
||||
virtual OnGwStatusChange& on_gw_status_change() = 0;
|
||||
virtual OnCancelReject &on_cancel_reject() = 0;
|
||||
private:
|
||||
BTS_NO_COPY(IExecutionGateway);
|
||||
};
|
||||
|
||||
class ExecutionGatewayFactory
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<IExecutionGateway> create_gateway(const config::JetFIX::Connection&, trace::PerfLog&, md::SecurityOracle);
|
||||
|
||||
};
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -143,7 +143,7 @@ void SODPosition::_zero_pos(Fill &pos, const Fill &fill, api::Side side) {
|
||||
}
|
||||
|
||||
bool SODPosition::add_fill_to_sod_pos(const Fill &fill) {
|
||||
if (_enabled && fill.timestamp().seconds() < _sod_time.tv_sec) {
|
||||
if (_enabled && fill.fill_status() != api::orderman::Fill::FILL_STATUS_BUSTED && fill.timestamp().seconds() < _sod_time.tv_sec) {
|
||||
if (!bts::admin::AdminServiceUtils::has_id(fill.internal_account_id())){
|
||||
LOG(persist, Error, "SODPosition::add_fill_to_sod_pos Could not find "
|
||||
"account_id for fill:{} account:{}",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "lib/orderman/orders/Order.h"
|
||||
#include "lib/orderman/securities/ISecurityDB.h"
|
||||
#include "lib/utils/inplace_function.h"
|
||||
#include "lib/utils/thread_manager.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
@@ -44,12 +45,28 @@ struct OrderManager::PImpl {
|
||||
mercury::Actor::SubHandle stored_fills_sub;
|
||||
OrderServicesData services_data;
|
||||
mercury::Stream<OrderManagerReadyEvent> pub_ready;
|
||||
std::thread background_thread;
|
||||
std::atomic<bool> shutdown = false;
|
||||
};
|
||||
|
||||
OrderManager::OrderManager(DynamicOrderRegistry const &b, trace::PerfLog &l,
|
||||
md::SecurityOracle o)
|
||||
: me(new PImpl(*this, b, l, o)) {}
|
||||
OrderManager::~OrderManager() {}
|
||||
: me(new PImpl(*this, b, l, o)) {
|
||||
auto id_gen = &me->services_data.id_gen;
|
||||
auto done = &me->shutdown;
|
||||
me->background_thread =
|
||||
threading::make_thread("oman_background", [id_gen, done]() {
|
||||
while (!(*done)) {
|
||||
id_gen->refill();
|
||||
sleep_for(10ms);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
OrderManager::~OrderManager() {
|
||||
me->shutdown = true;
|
||||
me->background_thread.join();
|
||||
}
|
||||
|
||||
void OrderManager::init() {
|
||||
subscribe<NewAdminDataEvent>(
|
||||
@@ -63,11 +80,13 @@ void OrderManager::init() {
|
||||
|
||||
void OrderManager::on_admin_data(const mercury::Update<NewAdminDataEvent> &m) {
|
||||
if (m.events) {
|
||||
|
||||
if (me->state == State::WAIT_ADMIN) {
|
||||
LOG(OrderMan, Info,
|
||||
"Order manager received admin data. Subscribing "
|
||||
"to security list now ");
|
||||
"Order manager received admin data. Subscribing to security list "
|
||||
"now ");
|
||||
for (auto &osd : me->services_data.sessions)
|
||||
osd->gw->on_admin_data(m);
|
||||
|
||||
me->state = State::WAIT_SEC;
|
||||
subscribe<NewSecuritiesEvent>([this](auto const &sec_update) {
|
||||
this->on_securities(sec_update);
|
||||
@@ -100,7 +119,7 @@ void OrderManager::on_securities(
|
||||
|
||||
// forward to execution gateways
|
||||
for (auto &osd : me->services_data.sessions)
|
||||
osd->gw.on_securities(update);
|
||||
osd->gw->on_securities(update);
|
||||
|
||||
if (update.events) {
|
||||
|
||||
@@ -444,19 +463,20 @@ void OrderManager::init_order_services() {
|
||||
// reject evets
|
||||
auto s_ptr = s.get();
|
||||
s->exe_report_pub = make_stream<NewExecutionReportEvent>(gw_name);
|
||||
s->gw.on_exe_report() = [s_ptr, this](auto const &er, auto const &t) {
|
||||
s->gw->on_exe_report() = [s_ptr, this](auto const &er, auto const &t) {
|
||||
publish(s_ptr->exe_report_pub, &er, t);
|
||||
};
|
||||
s->gw_status_change_pub = make_stream<GatewayStatusChangeEvent>(gw_name);
|
||||
s->gw.on_gw_status_change() = [s_ptr, this, gw_name](bool b) {
|
||||
s->gw->on_gw_status_change() = [s_ptr, this, gw_name](bool b) {
|
||||
publish(s_ptr->gw_status_change_pub, gw_name, b);
|
||||
};
|
||||
s->cancel_reject_pub = make_stream<CancelRejectEvent>(gw_name);
|
||||
s->gw.on_cancel_reject() = [s_ptr, this](auto const &k, auto const &msg) {
|
||||
s->gw->on_cancel_reject() = [s_ptr, this](auto const &k,
|
||||
auto const &msg) {
|
||||
publish(s_ptr->cancel_reject_pub, k, msg);
|
||||
};
|
||||
// handlers are ready so we can start processing fix events
|
||||
s->gw.start();
|
||||
s->gw->start();
|
||||
|
||||
reload_fix_buffer(*s);
|
||||
}
|
||||
@@ -539,7 +559,7 @@ void OrderManager::after_event() {
|
||||
auto scoped_do_work = trace::log_scope(me->services_data.log, {},
|
||||
"OrderManager::after_event");
|
||||
fix_stream.close();
|
||||
osd->gw.send_fix(osd->current_buffer, osd->current_trace);
|
||||
osd->gw->send_fix(osd->current_buffer, osd->current_trace);
|
||||
reload_fix_buffer(*osd);
|
||||
}
|
||||
}
|
||||
@@ -564,7 +584,7 @@ void OrderManager::on_poll(trace::PerfLog &log) {
|
||||
trace::log_scope(log, {}, "OrderManager::dispatch_incoming_fix_messages",
|
||||
utils::TimeStamp::Interval::from_microseconds(2));
|
||||
for (auto &osd : me->services_data.sessions)
|
||||
osd->gw.dispatch_incoming_fix_messages();
|
||||
osd->gw->dispatch_incoming_fix_messages();
|
||||
}
|
||||
|
||||
void OrderManager::publish_order_def_update(
|
||||
|
||||
@@ -46,6 +46,9 @@ class OrderServices {
|
||||
return ss.is_gateway_connected();
|
||||
}
|
||||
|
||||
uint64_t gen_id() {
|
||||
return _data->id_gen.next();
|
||||
}
|
||||
Governor &governor(SessionServices &ss) { return ss.governor(); }
|
||||
|
||||
void queue_fix(SessionServices &ss, jetfix::MessageTypes mt,
|
||||
|
||||
@@ -12,7 +12,9 @@ OrderServicesData::OrderServicesData(OrderManager &owner,
|
||||
order_factory(sec_db, order_router, b),
|
||||
last_timer_ev(
|
||||
Timer::now(),
|
||||
to<mercury::TimeStampStr>(datetime::FIX_timestamp(datetime::now()))) {
|
||||
to<mercury::TimeStampStr>(datetime::FIX_timestamp(datetime::now()))),
|
||||
id_gen("orderman_ids",5000)
|
||||
{
|
||||
|
||||
auto &all_connections = config::get<config::JetFIX>().connection();
|
||||
for (auto const &c : all_connections)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "lib/mercury/events/TimerEvent.h"
|
||||
#include "lib/md/SecurityOracle.h"
|
||||
#include "lib/orderman/actors/ExecutionGateway.h"
|
||||
#include "lib/orderman/actors/IExecutionGateway.h"
|
||||
#include "lib/orderman/events/ActivateOrderEvent.h"
|
||||
#include "lib/orderman/events/BookUpdateEvent.h"
|
||||
#include "lib/orderman/events/TickerUpdateEvent.h"
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "lib/orderman/limiter/Limiter.h"
|
||||
#include "lib/orderman/order_router/OrderRouter.h"
|
||||
#include "lib/utils/datetime.h"
|
||||
#include "lib/utils/Puid.h"
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
@@ -51,7 +52,10 @@ struct SessionServicesData {
|
||||
trace::PerfLog &log, md::SecurityOracle o)
|
||||
: session(cfg.name()), gw_connected(false), cfg(cfg),
|
||||
governor(cfg.max_order_msgs_per_window(), cfg.window_duration_msecs()),
|
||||
gw(cfg, log,o) {}
|
||||
gw(ExecutionGatewayFactory::create_gateway(cfg, log, o))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string session;
|
||||
std::vector<jetfix::OutFIXPtr> free_buffers;
|
||||
@@ -68,7 +72,7 @@ struct SessionServicesData {
|
||||
Governor governor;
|
||||
jetfix::OutFIXPtr current_buffer;
|
||||
trace::CorID current_trace;
|
||||
ExecutionGateway gw;
|
||||
std::unique_ptr<IExecutionGateway> gw;
|
||||
mercury::Stream<NewExecutionReportEvent> exe_report_pub;
|
||||
mercury::Stream<GatewayStatusChangeEvent> gw_status_change_pub;
|
||||
mercury::Stream<CancelRejectEvent> cancel_reject_pub;
|
||||
@@ -105,7 +109,8 @@ class OrderServicesData {
|
||||
mercury::Stream<OrderOpResultEvent> report_order_op_result_pub;
|
||||
mercury::TimerEvent last_timer_ev;
|
||||
std::vector<std::unique_ptr<SessionServicesData>> sessions;
|
||||
|
||||
utils::IDGenerator id_gen ;
|
||||
|
||||
SessionServicesData &get_session(std::string const &session_name) {
|
||||
for (auto &s : sessions)
|
||||
if (s->session == session_name)
|
||||
|
||||
@@ -57,14 +57,14 @@ class SessionServices {
|
||||
_gateway_status_sub = src._gateway_status_sub;
|
||||
return *this;
|
||||
}
|
||||
|
||||
config::JetFIX::Connection const &session_cfg() const {
|
||||
return _session_data->cfg;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string const &session_name() const { return _session_data->session; }
|
||||
|
||||
config::JetFIX::Connection const &session_cfg() const {
|
||||
return _session_data->cfg;
|
||||
}
|
||||
|
||||
void queue_fix(jetfix::MessageTypes mt, jetfix::FIXFragment const &f,
|
||||
trace::CorID const &corid) {
|
||||
auto &stream = _session_data->current_buffer->first_stream();
|
||||
|
||||
@@ -156,18 +156,6 @@ class OrderStateUpdateEvent : public mercury::Event<OrderStateUpdateEvent> {
|
||||
case api::orderman::OrderState::kProrata:
|
||||
result.mutable_prorata();
|
||||
break;
|
||||
case api::orderman::OrderState::kTwap:
|
||||
result.mutable_twap();
|
||||
break;
|
||||
case api::orderman::OrderState::kVwap:
|
||||
result.mutable_vwap();
|
||||
break;
|
||||
case api::orderman::OrderState::kPov:
|
||||
result.mutable_pov();
|
||||
break;
|
||||
case api::orderman::OrderState::kArrival:
|
||||
result.mutable_arrival();
|
||||
break;
|
||||
case api::orderman::OrderState::kDynamic:
|
||||
result.mutable_dynamic();
|
||||
break;
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
// order types
|
||||
#include "lib/orderman/order_factory/DynamicOrderRegistry.h"
|
||||
#include "lib/orderman/orders/DynamicOrder.h"
|
||||
#include "lib/orderman/orders/NativeOrder.h"
|
||||
#include "lib/orderman/orders/GLBXNativeOrder.h"
|
||||
#include "lib/orderman/orders/ICENativeOrder.h"
|
||||
#include "lib/orderman/orders/TimeBoxOrder.h"
|
||||
#include "lib/orderman/orders/TriggerOrder.h"
|
||||
#include "lib/orderman/orders/algo/AlgoWrapperOrder.h"
|
||||
@@ -23,11 +24,6 @@
|
||||
#include "lib/orderman/orders/algo/algo_orders/OffsetAlgo.h"
|
||||
#include "lib/orderman/orders/algo/algo_orders/ScratchAlgo.h"
|
||||
#include "lib/orderman/orders/algo/algo_orders/ProRataAlgo.h"
|
||||
#include "lib/orderman/orders/algo/algo_orders/bluex/TWAPAlgo.h"
|
||||
#include "lib/orderman/orders/algo/algo_orders/bluex/VWAPAlgo.h"
|
||||
#include "lib/orderman/orders/algo/algo_orders/bluex/POVAlgo.h"
|
||||
#include "lib/orderman/orders/algo/algo_orders/bluex/ArrivalPriceAlgo.h"
|
||||
|
||||
#include "lib/orderman/orders/book_algos/OCOOrder.h"
|
||||
#include "lib/orderman/orders/book_algos/PricerOrder.h"
|
||||
#include "lib/orderman/orders/spreader_orders/SpreaderOrder.h"
|
||||
@@ -118,6 +114,24 @@ Order &OrderFactory::recover(api::orderman::OrderRecord const &rec) {
|
||||
return order;
|
||||
}
|
||||
|
||||
NativeOrder *OrderFactory::make_order(const api::Venue exchange) {
|
||||
if (exchange == api::Venue::VENUE_ICE ||
|
||||
exchange == api::Venue::VENUE_SIMICE)
|
||||
return new ICENativeOrder();
|
||||
else
|
||||
return new GLBXNativeOrder();
|
||||
}
|
||||
|
||||
NativeOrder *
|
||||
OrderFactory::make_native_order(const api::orderman::OrderDefinition &def) {
|
||||
auto secptr = me->sec_db.resolve(SecurityKey(def.security_key()));
|
||||
if (secptr == nullptr)
|
||||
return new GLBXNativeOrder(); // GLBX Native can handle unresolved
|
||||
// securities
|
||||
else
|
||||
return make_order(secptr->exchange());
|
||||
}
|
||||
|
||||
Order &OrderFactory::recreate_from_exe_report(ExecutionReport const &r) {
|
||||
using namespace api::orderman;
|
||||
|
||||
@@ -126,7 +140,7 @@ Order &OrderFactory::recreate_from_exe_report(ExecutionReport const &r) {
|
||||
case NATIVE_ORDER_TYPE_LIMIT:
|
||||
case NATIVE_ORDER_TYPE_STOP:
|
||||
case NATIVE_ORDER_TYPE_STOP_LIMIT: {
|
||||
auto native_order = std::make_unique<NativeOrder>();
|
||||
std::unique_ptr<NativeOrder> native_order(make_order(r.exchange));
|
||||
native_order->_key = r.order_key;
|
||||
native_order->_parent_key = null_order_key();
|
||||
auto def = native_order->on_init_from_exe_report(
|
||||
@@ -156,7 +170,7 @@ Order &OrderFactory::allocate(OrderKey k, OrderKey pk,
|
||||
case CustomOrderDefinition::kStop:
|
||||
case CustomOrderDefinition::kStopLimit:
|
||||
case CustomOrderDefinition::kGlbxIceberg:
|
||||
order_ptr.reset(new NativeOrder());
|
||||
order_ptr.reset(make_native_order(def));
|
||||
break;
|
||||
case CustomOrderDefinition::kIceberg:
|
||||
order_ptr.reset(
|
||||
@@ -210,22 +224,6 @@ Order &OrderFactory::allocate(OrderKey k, OrderKey pk,
|
||||
order_ptr.reset(
|
||||
new orderman::AlgoWrapperOrder(std::make_unique<ProRataAlgo>()));
|
||||
break;
|
||||
case CustomOrderDefinition::kTwap:
|
||||
order_ptr.reset(
|
||||
new orderman::AlgoWrapperOrder(std::make_unique<TWAPAlgo>()));
|
||||
break;
|
||||
case CustomOrderDefinition::kVwap:
|
||||
order_ptr.reset(
|
||||
new orderman::AlgoWrapperOrder(std::make_unique<VWAPAlgo>()));
|
||||
break;
|
||||
case CustomOrderDefinition::kPov:
|
||||
order_ptr.reset(
|
||||
new orderman::AlgoWrapperOrder(std::make_unique<POVAlgo>()));
|
||||
break;
|
||||
case CustomOrderDefinition::kArrival:
|
||||
order_ptr.reset(
|
||||
new orderman::AlgoWrapperOrder(std::make_unique<ArrivalPriceAlgo>()));
|
||||
break;
|
||||
case CustomOrderDefinition::kDynamic: {
|
||||
order_ptr = me->dynamic_order_registry.build(
|
||||
def.custom_def().dynamic().dynamic_order_type());
|
||||
@@ -236,7 +234,6 @@ Order &OrderFactory::allocate(OrderKey k, OrderKey pk,
|
||||
order_ptr.reset(new orderman::DynamicOrder());
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case CustomOrderDefinition::kComposite:
|
||||
order_ptr.reset(new orderman::CompositeOrder());
|
||||
|
||||
@@ -11,6 +11,7 @@ class ISecurityDB;
|
||||
}
|
||||
namespace orderman {
|
||||
class Order;
|
||||
class NativeOrder;
|
||||
class DynamicOrderRegistry;
|
||||
} // namespace orderman
|
||||
namespace orderman {
|
||||
@@ -45,6 +46,8 @@ class OrderFactory : public IOrderFactory {
|
||||
private:
|
||||
Order &allocate(OrderKey k, OrderKey pk,
|
||||
api::orderman::OrderDefinition const &);
|
||||
NativeOrder* make_order(const api::Venue exchange);
|
||||
NativeOrder* make_native_order(const api::orderman::OrderDefinition& def);
|
||||
struct PImpl;
|
||||
|
||||
std::unique_ptr<PImpl> me;
|
||||
|
||||
@@ -35,6 +35,10 @@ public:
|
||||
mercury::TimeStampStr transact_time;
|
||||
config::JetFIX::Connection const *cfg;
|
||||
std::string msg;
|
||||
api::Venue exchange;
|
||||
int64_t ice_cl_ord_id;
|
||||
int32_t ice_company_id;
|
||||
std::string memo;
|
||||
};
|
||||
|
||||
}}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "lib/jetfix/codec/i32_toa.h"
|
||||
#include "lib/jetfix/codec/MessageDefinitions.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include "lib/utils/base62.h"
|
||||
|
||||
namespace bts {
|
||||
namespace api {class Security;}
|
||||
@@ -17,6 +18,8 @@ constexpr int clordid_sz() {return 20;}
|
||||
constexpr int price_sz() {return 17;}
|
||||
constexpr int quantity_sz() {return 6;}
|
||||
constexpr int max_show_sz() {return 6;}
|
||||
constexpr int memo_sz() {return 12;}
|
||||
constexpr int ice_orderid_sz() {return 12;}
|
||||
|
||||
inline void encode_clorid(OrderKey ok, SecurityKey sk,std::string *out) {
|
||||
u32_toa(sk.value(),&((*out)[0]),clordid_sz()/2);
|
||||
@@ -38,8 +41,7 @@ inline void decode_clorid(std::string const&in, OrderKey *ok, SecurityKey *sk)
|
||||
|
||||
template <class MSG>
|
||||
OrderKey get_order_key(MSG const &msg)
|
||||
{
|
||||
|
||||
{
|
||||
bts_assert(msg.template has<jetfix::fix::ClOrdID> ());
|
||||
OrderKey result;
|
||||
SecurityKey dummy;
|
||||
@@ -47,4 +49,47 @@ OrderKey get_order_key(MSG const &msg)
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void encode_memo(OrderKey ok, SecurityKey sk, std::string *out)
|
||||
{
|
||||
auto ok_string = utils::to_base_62(ok.value());
|
||||
auto sk_string = utils::to_base_62(sk.value());
|
||||
bts_assert_msg(ok_string.size() == 6 && sk_string.size() == 6, "base62 encoding didn't work");
|
||||
*out = ok_string + sk_string;
|
||||
}
|
||||
|
||||
inline void decode_memo(const std::string& in, OrderKey* ok, SecurityKey* sk)
|
||||
{
|
||||
bts_assert(in.size() == memo_sz());
|
||||
char buffer[memo_sz()/2+1];
|
||||
buffer[memo_sz()/2] = 0;
|
||||
std::memcpy(buffer,&in[0],memo_sz()/2);
|
||||
*ok = OrderKey( utils::from_base_62(std::string(buffer)) );
|
||||
|
||||
std::memcpy(buffer,&in[memo_sz()/2],memo_sz()/2);
|
||||
*sk = SecurityKey( utils::from_base_62(std::string(buffer)) );
|
||||
}
|
||||
|
||||
template <class MSG>
|
||||
std::string get_ice_order_id_string(const MSG& msg)
|
||||
{
|
||||
bts_assert(msg.template has<jetfix::fix::Int_OrderID>());
|
||||
std::string oid_string(ice_orderid_sz(), ' ');
|
||||
|
||||
int64_t id = msg.template get<jetfix::fix::Int_OrderID>();
|
||||
u64_toa(id, &(oid_string[0]), ice_orderid_sz() );
|
||||
return oid_string;
|
||||
}
|
||||
|
||||
template <class MSG>
|
||||
std::string get_ice_clord_id_string(const MSG& msg)
|
||||
{
|
||||
bts_assert(msg.template has<jetfix::fix::Int_ClOrdID>());
|
||||
std::string oid_string(ice_orderid_sz(), ' ');
|
||||
|
||||
int64_t id = msg.template get<jetfix::fix::Int_ClOrdID>();
|
||||
u64_toa(id, &(oid_string[0]), ice_orderid_sz() );
|
||||
return oid_string;
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
+44
-44
@@ -1,4 +1,4 @@
|
||||
#include "NativeOrder.h"
|
||||
#include "GLBXNativeOrder.h"
|
||||
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/config/config.h"
|
||||
@@ -28,7 +28,7 @@ using namespace api::orderman;
|
||||
|
||||
OrderStatus map_external_status(NativeOrderStatus);
|
||||
|
||||
struct NativeOrder::PImpl {
|
||||
struct GLBXNativeOrder::PImpl {
|
||||
PImpl()
|
||||
: services(nullptr), session_services(), sec(nullptr),
|
||||
previous_position_contribution(0), definition(), state(),
|
||||
@@ -72,14 +72,14 @@ struct NativeOrder::PImpl {
|
||||
std::optional<std::pair<Price, Quantity>> buffered_update;
|
||||
};
|
||||
|
||||
NativeOrder::NativeOrder() : me(new PImpl()) {}
|
||||
GLBXNativeOrder::GLBXNativeOrder() : me(new PImpl()) {}
|
||||
|
||||
OrderDefinition const &NativeOrder::definition() const {
|
||||
OrderDefinition const &GLBXNativeOrder::definition() const {
|
||||
return me->definition;
|
||||
}
|
||||
|
||||
void NativeOrder::on_init_new(OrderDefinition const &def,
|
||||
const PreActivationOrderServices &serv) {
|
||||
void GLBXNativeOrder::on_init_new(OrderDefinition const &def,
|
||||
const PreActivationOrderServices &serv) {
|
||||
// order was just created.
|
||||
me->definition = def;
|
||||
|
||||
@@ -161,8 +161,8 @@ void NativeOrder::on_init_new(OrderDefinition const &def,
|
||||
init_fix();
|
||||
}
|
||||
|
||||
void NativeOrder::on_init_recovered(OrderRecord const &rec,
|
||||
const PreActivationOrderServices &serv) {
|
||||
void GLBXNativeOrder::on_init_recovered(OrderRecord const &rec,
|
||||
const PreActivationOrderServices &serv) {
|
||||
// order was recovered from our orders database or from an execution
|
||||
// report
|
||||
|
||||
@@ -231,8 +231,8 @@ void NativeOrder::on_init_recovered(OrderRecord const &rec,
|
||||
}
|
||||
|
||||
api::orderman::OrderDefinition
|
||||
NativeOrder::on_init_from_exe_report(ExecutionReport const &er,
|
||||
const PreActivationOrderServices &os) {
|
||||
GLBXNativeOrder::on_init_from_exe_report(ExecutionReport const &er,
|
||||
const PreActivationOrderServices &os) {
|
||||
auto k = er.order_key;
|
||||
|
||||
OrderRecord orecord;
|
||||
@@ -330,10 +330,10 @@ NativeOrder::on_init_from_exe_report(ExecutionReport const &er,
|
||||
return orecord.def();
|
||||
}
|
||||
|
||||
NativeOrder::~NativeOrder() {}
|
||||
GLBXNativeOrder::~GLBXNativeOrder() {}
|
||||
|
||||
void NativeOrder::warm_up_activate(OrderServicesData &data,
|
||||
OrderServices &services) {
|
||||
void GLBXNativeOrder::warm_up_activate(OrderServicesData &data,
|
||||
OrderServices &services) {
|
||||
bts_assert(!me->services);
|
||||
me->services = &services;
|
||||
|
||||
@@ -358,9 +358,9 @@ void NativeOrder::warm_up_activate(OrderServicesData &data,
|
||||
}
|
||||
|
||||
OrderOpResult
|
||||
NativeOrder::_on_activate(log::Level reject_level, log::Level transition_level,
|
||||
Price p, Quantity q,
|
||||
bts::orderman::OrderServices &services) {
|
||||
GLBXNativeOrder::_on_activate(log::Level reject_level, log::Level transition_level,
|
||||
Price p, Quantity q,
|
||||
bts::orderman::OrderServices &services) {
|
||||
me->state.set_price(p.value());
|
||||
me->state.set_quantity(q.value());
|
||||
me->state.set_filled_quantity(0);
|
||||
@@ -467,8 +467,8 @@ NativeOrder::_on_activate(log::Level reject_level, log::Level transition_level,
|
||||
return OrderOpResult{};
|
||||
}
|
||||
|
||||
OrderOpResult NativeOrder::on_activate(Price p, Quantity q,
|
||||
bts::orderman::OrderServices &services) {
|
||||
OrderOpResult GLBXNativeOrder::on_activate(Price p, Quantity q,
|
||||
bts::orderman::OrderServices &services) {
|
||||
bts_assert(!me->services);
|
||||
me->services = &services;
|
||||
auto result = OrderOpResult{};
|
||||
@@ -476,7 +476,7 @@ OrderOpResult NativeOrder::on_activate(Price p, Quantity q,
|
||||
|
||||
case ORDER_STATUS_INACTIVE: {
|
||||
auto scoped_log =
|
||||
services.log_scope("NativeOrder::on_activate", key().value());
|
||||
services.log_scope("GLBXNativeOrder::on_activate", key().value());
|
||||
// this is a brand new order
|
||||
|
||||
result = _on_activate(Warn, Info, p, q, services);
|
||||
@@ -570,19 +570,19 @@ OrderOpResult NativeOrder::on_activate(Price p, Quantity q,
|
||||
return result;
|
||||
}
|
||||
|
||||
OrderOpResult NativeOrder::on_update(Price p, Quantity q) {
|
||||
OrderOpResult GLBXNativeOrder::on_update(Price p, Quantity q) {
|
||||
api::orderman::Update update;
|
||||
update.set_price(p.value());
|
||||
update.set_quantity(q.value());
|
||||
return on_update(update);
|
||||
}
|
||||
|
||||
OrderOpResult NativeOrder::on_update(api::orderman::Update const &update) {
|
||||
OrderOpResult GLBXNativeOrder::on_update(api::orderman::Update const &update) {
|
||||
auto p = Price(update.price());
|
||||
auto q = Quantity(update.quantity());
|
||||
|
||||
auto scoped_log =
|
||||
me->services->log_scope("NativeOrder::on_update", key().value());
|
||||
me->services->log_scope("GLBXNativeOrder::on_update", key().value());
|
||||
auto result = OrderOpResult{};
|
||||
|
||||
switch (me->state.status()) {
|
||||
@@ -707,9 +707,9 @@ OrderOpResult NativeOrder::on_update(api::orderman::Update const &update) {
|
||||
return result;
|
||||
}
|
||||
|
||||
OrderOpResult NativeOrder::on_detach() { return OrderOpResult{}; }
|
||||
OrderOpResult GLBXNativeOrder::on_detach() { return OrderOpResult{}; }
|
||||
|
||||
void NativeOrder::on_attached(
|
||||
void GLBXNativeOrder::on_attached(
|
||||
api::orderman::OrderDefinition const &new_parent) {
|
||||
switch (me->state.status()) {
|
||||
|
||||
@@ -764,9 +764,9 @@ void NativeOrder::on_attached(
|
||||
}
|
||||
}
|
||||
|
||||
OrderOpResult NativeOrder::on_cancel() {
|
||||
OrderOpResult GLBXNativeOrder::on_cancel() {
|
||||
auto scoped_log =
|
||||
me->services->log_scope("NativeOrder::on_cancel", key().value());
|
||||
me->services->log_scope("GLBXNativeOrder::on_cancel", key().value());
|
||||
auto result = OrderOpResult{};
|
||||
|
||||
switch (me->state.status()) {
|
||||
@@ -822,7 +822,7 @@ OrderOpResult NativeOrder::on_cancel() {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NativeOrder::is_old_exe_report(
|
||||
bool GLBXNativeOrder::is_old_exe_report(
|
||||
api::orderman::NativeOrderState &native_state,
|
||||
const NewExecutionReportEvent &er) const {
|
||||
if (native_state.last_transact_time().size() !=
|
||||
@@ -844,9 +844,9 @@ bool NativeOrder::is_old_exe_report(
|
||||
return true;
|
||||
}
|
||||
|
||||
void NativeOrder::on_exe_report(const NewExecutionReportEvent &er) {
|
||||
void GLBXNativeOrder::on_exe_report(const NewExecutionReportEvent &er) {
|
||||
auto scoped_log =
|
||||
me->services->log_scope("NativeOrder::on_exe_report", key().value());
|
||||
me->services->log_scope("GLBXNativeOrder::on_exe_report", key().value());
|
||||
|
||||
auto &state = me->state;
|
||||
auto &native_state = get_native_state(state);
|
||||
@@ -969,7 +969,7 @@ void NativeOrder::on_exe_report(const NewExecutionReportEvent &er) {
|
||||
}
|
||||
}
|
||||
|
||||
void NativeOrder::on_cancel_reject(const orderman::CancelRejectEvent &cr) {
|
||||
void GLBXNativeOrder::on_cancel_reject(const orderman::CancelRejectEvent &cr) {
|
||||
LOG(OrderMan, Warn, "Cancel reject received for order {}", key().value());
|
||||
|
||||
switch (me->state.status()) {
|
||||
@@ -997,7 +997,7 @@ void NativeOrder::on_cancel_reject(const orderman::CancelRejectEvent &cr) {
|
||||
}
|
||||
}
|
||||
|
||||
void NativeOrder::on_gateway_status(const GatewayStatusChangeEvent &ev) {
|
||||
void GLBXNativeOrder::on_gateway_status(const GatewayStatusChangeEvent &ev) {
|
||||
if (ev.is_connected) {
|
||||
switch (me->state.status()) {
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
@@ -1057,7 +1057,7 @@ void NativeOrder::on_gateway_status(const GatewayStatusChangeEvent &ev) {
|
||||
report_state();
|
||||
}
|
||||
|
||||
void NativeOrder::update_working_position() {
|
||||
void GLBXNativeOrder::update_working_position() {
|
||||
if (me->sec) {
|
||||
auto current_position = position_contribution();
|
||||
auto previous_position = me->previous_position_contribution;
|
||||
@@ -1082,12 +1082,12 @@ void NativeOrder::update_working_position() {
|
||||
key().value(), me->definition.security_key());
|
||||
}
|
||||
|
||||
void NativeOrder::report_state() {
|
||||
void GLBXNativeOrder::report_state() {
|
||||
update_working_position();
|
||||
me->services->report_state(me->state);
|
||||
}
|
||||
|
||||
void NativeOrder::init_fix() {
|
||||
void GLBXNativeOrder::init_fix() {
|
||||
bts_assert(me->sec);
|
||||
|
||||
using namespace jetfix;
|
||||
@@ -1253,7 +1253,7 @@ void NativeOrder::init_fix() {
|
||||
}
|
||||
}
|
||||
|
||||
void NativeOrder::add_exchange_order_id_to_fix() {
|
||||
void GLBXNativeOrder::add_exchange_order_id_to_fix() {
|
||||
bts_assert(has_exchange_order_id());
|
||||
me->update_encoding.add<jetfix::fix::OrderID>(me->exchange_order_id);
|
||||
me->cancel_encoding.add<jetfix::fix::OrderID>(me->exchange_order_id);
|
||||
@@ -1296,16 +1296,16 @@ OrderStatus map_external_status(NativeOrderStatus status) {
|
||||
return ORDER_STATUS_ERROR;
|
||||
}
|
||||
|
||||
bool NativeOrder::has_exchange_order_id() {
|
||||
bool GLBXNativeOrder::has_exchange_order_id() {
|
||||
return me->exchange_order_id.size();
|
||||
}
|
||||
|
||||
void NativeOrder::transition(api::orderman::OrderStatus new_status,
|
||||
void GLBXNativeOrder::transition(api::orderman::OrderStatus new_status,
|
||||
std::string const &msg) {
|
||||
transition(Info, new_status, msg);
|
||||
}
|
||||
|
||||
void NativeOrder::transition(log::Level level,
|
||||
void GLBXNativeOrder::transition(log::Level level,
|
||||
api::orderman::OrderStatus new_status,
|
||||
std::string const &msg) {
|
||||
auto const &from = OrderStatus_Name(me->state.status());
|
||||
@@ -1317,7 +1317,7 @@ void NativeOrder::transition(log::Level level,
|
||||
me->state.set_last_msg(msg);
|
||||
}
|
||||
|
||||
void NativeOrder::transition(api::orderman::OrderStatus new_status) {
|
||||
void GLBXNativeOrder::transition(api::orderman::OrderStatus new_status) {
|
||||
auto const &from = OrderStatus_Name(me->state.status());
|
||||
auto const &to = OrderStatus_Name(new_status);
|
||||
if (from != to)
|
||||
@@ -1330,7 +1330,7 @@ void NativeOrder::transition(api::orderman::OrderStatus new_status) {
|
||||
me->state.set_status(new_status);
|
||||
}
|
||||
|
||||
void NativeOrder::transition_to_error(
|
||||
void GLBXNativeOrder::transition_to_error(
|
||||
api::orderman::NativeOrderState::SubError sub_error,
|
||||
std::string const &msg) {
|
||||
me->state.mutable_limit()->mutable_native_state()->set_sub_error_code(
|
||||
@@ -1338,7 +1338,7 @@ void NativeOrder::transition_to_error(
|
||||
transition(ORDER_STATUS_ERROR, msg);
|
||||
}
|
||||
|
||||
Quantity NativeOrder::position_contribution() {
|
||||
Quantity GLBXNativeOrder::position_contribution() {
|
||||
switch (me->state.status()) {
|
||||
|
||||
case ORDER_STATUS_WORKING:
|
||||
@@ -1363,7 +1363,7 @@ Quantity NativeOrder::position_contribution() {
|
||||
return Quantity(0);
|
||||
}
|
||||
|
||||
bool NativeOrder::terminal_state(api::orderman::OrderStatus status) const {
|
||||
bool GLBXNativeOrder::terminal_state(api::orderman::OrderStatus status) const {
|
||||
switch (status) {
|
||||
|
||||
case ORDER_STATUS_COMPLETED:
|
||||
@@ -1389,7 +1389,7 @@ bool NativeOrder::terminal_state(api::orderman::OrderStatus status) const {
|
||||
}
|
||||
|
||||
api::orderman::NativeOrderState &
|
||||
NativeOrder::get_native_state(api::orderman::OrderState &st) {
|
||||
GLBXNativeOrder::get_native_state(api::orderman::OrderState &st) {
|
||||
switch (st.custom_case()) {
|
||||
case OrderState::kMarket:
|
||||
return *st.mutable_market()->mutable_native_state();
|
||||
@@ -1410,7 +1410,7 @@ NativeOrder::get_native_state(api::orderman::OrderState &st) {
|
||||
return *st.mutable_stop_limit()->mutable_native_state();
|
||||
}
|
||||
|
||||
void NativeOrder::ignore_or_cancel(std::string const &msg,
|
||||
void GLBXNativeOrder::ignore_or_cancel(std::string const &msg,
|
||||
api::orderman::OrderError error,
|
||||
OrderOpResult *out) {
|
||||
if (parent_key() == null_order_key())
|
||||
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/orderman/orders/NativeOrder.h"
|
||||
#include "lib/tracing/PerfLog.h"
|
||||
#include <memory>
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
struct RoutingRecord;
|
||||
class NewExecutionReportEvent;
|
||||
class CancelRejectEvent;
|
||||
class GatewayStatusChangeEvent;
|
||||
class ExecutionReport;
|
||||
|
||||
class GLBXNativeOrder : public NativeOrder {
|
||||
public:
|
||||
GLBXNativeOrder();
|
||||
~GLBXNativeOrder() override;
|
||||
|
||||
api::orderman::OrderDefinition const &definition() const override;
|
||||
void on_init_new(api::orderman::OrderDefinition const &,
|
||||
const PreActivationOrderServices &) override;
|
||||
void on_init_recovered(api::orderman::OrderRecord const &,
|
||||
const PreActivationOrderServices &) override;
|
||||
|
||||
OrderOpResult on_activate(Price, Quantity, OrderServices &) override;
|
||||
OrderOpResult on_update(Price, Quantity) override;
|
||||
OrderOpResult on_update(api::orderman::Update const &) override;
|
||||
OrderOpResult on_detach() override;
|
||||
OrderOpResult on_cancel() override;
|
||||
void on_attached(api::orderman::OrderDefinition const &new_parent) override;
|
||||
|
||||
api::orderman::OrderDefinition
|
||||
on_init_from_exe_report(ExecutionReport const &,
|
||||
const PreActivationOrderServices &) override;
|
||||
void ignore_or_cancel(std::string const &,
|
||||
api::orderman::OrderError,
|
||||
OrderOpResult *out) ;
|
||||
|
||||
protected:
|
||||
void warm_up_activate(OrderServicesData &, OrderServices &) override;
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
void on_exe_report(const NewExecutionReportEvent &);
|
||||
void on_cancel_reject(const CancelRejectEvent &);
|
||||
void on_gateway_status(const GatewayStatusChangeEvent &);
|
||||
void report_state();
|
||||
OrderOpResult _on_activate(log::Level reject_level,
|
||||
log::Level transition_level, Price p, Quantity q,
|
||||
bts::orderman::OrderServices &services);
|
||||
void init_fix();
|
||||
void add_exchange_order_id_to_fix();
|
||||
|
||||
void transition(log::Level,
|
||||
api::orderman::OrderStatus new_state,
|
||||
std::string const &msg);
|
||||
void transition(api::orderman::OrderStatus new_state,
|
||||
std::string const &msg);
|
||||
void transition(api::orderman::OrderStatus new_state);
|
||||
void transition_to_error(api::orderman::NativeOrderState::SubError sub_error,
|
||||
std::string const &msg);
|
||||
|
||||
void update_working_position();
|
||||
bool has_exchange_order_id();
|
||||
Quantity position_contribution();
|
||||
bool is_old_exe_report(api::orderman::NativeOrderState &,
|
||||
const NewExecutionReportEvent &) const;
|
||||
bool terminal_state(api::orderman::OrderStatus status) const;
|
||||
api::orderman::NativeOrderState &
|
||||
get_native_state(api::orderman::OrderState &);
|
||||
};
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/orderman/orders/NativeOrder.h"
|
||||
#include "lib/tracing/PerfLog.h"
|
||||
#include <memory>
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
struct RoutingRecord;
|
||||
class NewExecutionReportEvent;
|
||||
class CancelRejectEvent;
|
||||
class GatewayStatusChangeEvent;
|
||||
class ExecutionReport;
|
||||
|
||||
class ICENativeOrder : public NativeOrder {
|
||||
public:
|
||||
ICENativeOrder();
|
||||
~ICENativeOrder() override;
|
||||
|
||||
const api::orderman::OrderDefinition& definition() const override;
|
||||
void on_init_new(const api::orderman::OrderDefinition&,
|
||||
const PreActivationOrderServices&) override;
|
||||
void on_init_recovered(const api::orderman::OrderRecord&,
|
||||
const PreActivationOrderServices &) override;
|
||||
|
||||
OrderOpResult on_activate(Price, Quantity, OrderServices &) override;
|
||||
OrderOpResult on_update(Price, Quantity) override;
|
||||
OrderOpResult on_update(const api::orderman::Update&) override;
|
||||
OrderOpResult on_detach() override;
|
||||
OrderOpResult on_cancel() override;
|
||||
void on_attached(const api::orderman::OrderDefinition &new_parent) override;
|
||||
|
||||
api::orderman::OrderDefinition
|
||||
on_init_from_exe_report(const ExecutionReport &, const PreActivationOrderServices &) override;
|
||||
void ignore_or_cancel(const std::string&, api::orderman::OrderError, OrderOpResult* out);
|
||||
|
||||
protected:
|
||||
void warm_up_activate(OrderServicesData &, OrderServices &) override;
|
||||
void init_recovered_common(const api::orderman::OrderRecord &,
|
||||
const PreActivationOrderServices &);
|
||||
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
void on_exe_report(const NewExecutionReportEvent &);
|
||||
void on_cancel_reject(const CancelRejectEvent &);
|
||||
void on_gateway_status(const GatewayStatusChangeEvent &);
|
||||
void report_state();
|
||||
OrderOpResult _on_activate(log::Level reject_level,
|
||||
log::Level transition_level, Price p, Quantity q,
|
||||
bts::orderman::OrderServices &services);
|
||||
void init_fix();
|
||||
void add_exchange_order_id_to_fix();
|
||||
|
||||
void transition(log::Level,
|
||||
api::orderman::OrderStatus new_state,
|
||||
const std::string& msg);
|
||||
void transition(api::orderman::OrderStatus new_state,
|
||||
const std::string& msg);
|
||||
void transition(api::orderman::OrderStatus new_state);
|
||||
void transition_to_error(api::orderman::NativeOrderState::SubError sub_error,
|
||||
const std::string& msg);
|
||||
|
||||
void update_working_position();
|
||||
bool has_exchange_order_id();
|
||||
Quantity position_contribution();
|
||||
bool is_old_exe_report(api::orderman::NativeOrderState &,
|
||||
const NewExecutionReportEvent &) const;
|
||||
bool terminal_state(api::orderman::OrderStatus status) const;
|
||||
api::orderman::NativeOrderState &
|
||||
get_native_state(api::orderman::OrderState &);
|
||||
|
||||
int64_t get_new_clordid();
|
||||
int64_t get_clordid(uint64_t);
|
||||
void setup_ids(const std::string& sender_compid);
|
||||
void generate_update_ids(const std::string&);
|
||||
void generate_cancel_ids(const std::string&);
|
||||
};
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -2,75 +2,19 @@
|
||||
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/orderman/orders/Order.h"
|
||||
#include "lib/tracing/PerfLog.h"
|
||||
#include <memory>
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
struct RoutingRecord;
|
||||
class NewExecutionReportEvent;
|
||||
class CancelRejectEvent;
|
||||
class GatewayStatusChangeEvent;
|
||||
class ExecutionReport;
|
||||
|
||||
class NativeOrder : public Order {
|
||||
public:
|
||||
NativeOrder();
|
||||
~NativeOrder() override;
|
||||
|
||||
api::orderman::OrderDefinition const &definition() const;
|
||||
void on_init_new(api::orderman::OrderDefinition const &,
|
||||
const PreActivationOrderServices &) override;
|
||||
void on_init_recovered(api::orderman::OrderRecord const &,
|
||||
const PreActivationOrderServices &) override;
|
||||
|
||||
OrderOpResult on_activate(Price, Quantity, OrderServices &) override;
|
||||
OrderOpResult on_update(Price, Quantity) override;
|
||||
OrderOpResult on_update(api::orderman::Update const &) override;
|
||||
OrderOpResult on_detach() override;
|
||||
OrderOpResult on_cancel() override;
|
||||
void on_attached(api::orderman::OrderDefinition const &new_parent) override;
|
||||
NativeOrder() = default;
|
||||
~NativeOrder() override {};
|
||||
|
||||
virtual api::orderman::OrderDefinition const &definition() const = 0;
|
||||
api::orderman::OrderDefinition
|
||||
on_init_from_exe_report(ExecutionReport const &,
|
||||
const PreActivationOrderServices &);
|
||||
|
||||
protected:
|
||||
void warm_up_activate(OrderServicesData &, OrderServices &) override;
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
void on_exe_report(const NewExecutionReportEvent &);
|
||||
void on_cancel_reject(const CancelRejectEvent &);
|
||||
void on_gateway_status(const GatewayStatusChangeEvent &);
|
||||
void report_state();
|
||||
OrderOpResult _on_activate(log::Level reject_level,
|
||||
log::Level transition_level, Price p, Quantity q,
|
||||
bts::orderman::OrderServices &services);
|
||||
void init_fix();
|
||||
void add_exchange_order_id_to_fix();
|
||||
|
||||
void transition(log::Level,
|
||||
api::orderman::OrderStatus new_state,
|
||||
std::string const &msg);
|
||||
void transition(api::orderman::OrderStatus new_state,
|
||||
std::string const &msg);
|
||||
void transition(api::orderman::OrderStatus new_state);
|
||||
void transition_to_error(api::orderman::NativeOrderState::SubError sub_error,
|
||||
std::string const &msg);
|
||||
|
||||
void update_working_position();
|
||||
bool has_exchange_order_id();
|
||||
Quantity position_contribution();
|
||||
bool is_old_exe_report(api::orderman::NativeOrderState &,
|
||||
const NewExecutionReportEvent &) const;
|
||||
bool terminal_state(api::orderman::OrderStatus status) const;
|
||||
api::orderman::NativeOrderState &
|
||||
get_native_state(api::orderman::OrderState &);
|
||||
void ignore_or_cancel(std::string const &,
|
||||
api::orderman::OrderError,
|
||||
OrderOpResult *out) ;
|
||||
virtual on_init_from_exe_report(ExecutionReport const &, const PreActivationOrderServices &) = 0;
|
||||
};
|
||||
|
||||
} // namespace orderman
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
#include "lib/orderman/orders/algo/algo_orders/bluex/ArrivalPriceAlgo.h"
|
||||
#include "lib/orderman/orders/algo/IAlgoServices.h"
|
||||
#include "lib/orderman/orders/algo/DynamicHelpers.h"
|
||||
|
||||
#include "lib/orderman/order_factory/IOrderFactory.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderUtils.h"
|
||||
#include "lib/os/os.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
using namespace api::orderman;
|
||||
|
||||
enum class ArrivalPriceAlgo::Status { WAITING_FOR_MD, WAITING_TO_SCRATCH, SCRATCHED };
|
||||
|
||||
struct ArrivalPriceAlgo::PImpl
|
||||
{
|
||||
IAlgoServices *algo;
|
||||
OrderDefinition definition;
|
||||
|
||||
Quantity scratch_threshold;
|
||||
Price chase_diff;
|
||||
Status status = Status::WAITING_FOR_MD;
|
||||
OrderKey child_key = null_order_key();
|
||||
ChildTemplate *child_template = nullptr;
|
||||
Book last_book;
|
||||
Book book_at_inception;
|
||||
Price scratch_price=Price(os::nan());
|
||||
};
|
||||
|
||||
ArrivalPriceAlgo::ArrivalPriceAlgo() : me(new PImpl()) {}
|
||||
ArrivalPriceAlgo::~ArrivalPriceAlgo() {}
|
||||
IAlgoServices &ArrivalPriceAlgo::algo() const { return *me->algo; }
|
||||
|
||||
OrderOpResult ArrivalPriceAlgo::do_before_launch(IBeforeLaunchAlgoServices &serv)
|
||||
{
|
||||
const auto& def = serv.definition();
|
||||
bts_assert(def.has_custom_def());
|
||||
bts_assert(def.custom_def().has_scratch());
|
||||
// Validate the scratch part of the definition
|
||||
auto &scratch = def.custom_def().scratch();
|
||||
if (!scratch.has_child() && OrderKey(def.attach_target_order_key()) == null_order_key())
|
||||
{
|
||||
return OrderOpResult{ ORDER_ERROR_INVALID_ORDER_DEFINITON,
|
||||
"Scratch order must have either a child order definition or an order to attach to"};
|
||||
}
|
||||
if (!serv.is_attaching())
|
||||
{
|
||||
// if we are not attaching create a child template so we can
|
||||
// quickly launch our child when the time comes.
|
||||
auto child_def = def;
|
||||
*child_def.mutable_custom_def() = def.custom_def().scratch().child();
|
||||
me->child_template = &(serv.make_child_template(child_def));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void ArrivalPriceAlgo::do_launch(IAlgoServices &algo)
|
||||
{
|
||||
me->algo = &algo;
|
||||
update_scratch_threshold();
|
||||
bts_assert(me->child_template);
|
||||
me->child_key = algo.launch_child(*me->child_template, algo.price(), algo.quantity());
|
||||
algo.subscribe_book(SecurityKey(algo.security().id()));
|
||||
}
|
||||
|
||||
void ArrivalPriceAlgo::do_launch_attached(IAlgoServices &algo, OrderKey k, ChildState st)
|
||||
{
|
||||
me->algo = &algo;
|
||||
update_scratch_threshold();
|
||||
me->child_key = k;
|
||||
algo.subscribe_book(SecurityKey(algo.security().id()));
|
||||
on_child_change(k, st);
|
||||
}
|
||||
|
||||
void ArrivalPriceAlgo::do_update(api::orderman::Update const &update)
|
||||
{
|
||||
LOG(OrderMan, Diag, "ScratchOrder order {} receiving update: {}", algo().order_key().value(), utils::pb::to_string(update));
|
||||
|
||||
if (update.has_custom() && !update.custom().has_scratch())
|
||||
{
|
||||
algo().terminate_error("Invalid update");
|
||||
return;
|
||||
}
|
||||
|
||||
Update child_update;
|
||||
Price price_to_pass = get_price_to_pass(Price(update.price()));
|
||||
child_update.set_price(price_to_pass.value());
|
||||
child_update.set_quantity(update.quantity());
|
||||
if (update.has_custom())
|
||||
{
|
||||
update_scratch_threshold();
|
||||
auto &scratch_update = update.custom().scratch();
|
||||
*child_update.mutable_custom() = scratch_update.child();
|
||||
}
|
||||
algo().update_child(me->child_key, child_update);
|
||||
|
||||
// If we were not yet scratched it is possible we now can, since we
|
||||
// could have changed the scratch_threshold
|
||||
if (me->status == Status::WAITING_TO_SCRATCH)
|
||||
try_to_scratch();
|
||||
}
|
||||
|
||||
void ArrivalPriceAlgo::on_book(SecurityKey, Book const &b)
|
||||
{
|
||||
me->last_book = b;
|
||||
|
||||
LOG(OrderMan, Diag, "ScratchOrder order {} on book. BID: {}@{} ASK: {}@{}",
|
||||
algo().order_key().value(), b.side(api::SIDE_BUY)[0].size(),
|
||||
b.side(api::SIDE_BUY)[0].price(), b.side(api::SIDE_SELL)[0].size(),
|
||||
b.side(api::SIDE_SELL)[0].price());
|
||||
|
||||
switch (me->status)
|
||||
{
|
||||
case Status::WAITING_FOR_MD:
|
||||
{
|
||||
auto other_side = securities::other_side(algo().definition().side());
|
||||
auto &other_side_top = me->last_book.side(other_side)[0];
|
||||
|
||||
if (other_side_top.size() > 0)
|
||||
{
|
||||
me->status = Status::WAITING_TO_SCRATCH;
|
||||
me->book_at_inception = b;
|
||||
LOG(OrderMan, Diag,
|
||||
"ScratchOrder order {} receiving first book: {} Target: {}",
|
||||
algo().order_key().value(), me->scratch_threshold.value(),
|
||||
other_side_top.price());
|
||||
try_to_scratch();
|
||||
}
|
||||
} break;
|
||||
case Status::SCRATCHED:
|
||||
break;
|
||||
case Status::WAITING_TO_SCRATCH:
|
||||
try_to_scratch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArrivalPriceAlgo::try_to_scratch()
|
||||
{
|
||||
bts_assert(me->status == Status::WAITING_TO_SCRATCH);
|
||||
auto my_side = algo().definition().side();
|
||||
auto other_side = securities::other_side(my_side);
|
||||
|
||||
Quantity my_quan;
|
||||
auto &my_side_psz = me->last_book.side(my_side)[0];
|
||||
auto &other_side_psz = me->last_book.side(other_side)[0];
|
||||
auto other_side_price = Price(other_side_psz.price());
|
||||
auto inception_other_side_price = Price(me->book_at_inception.side(other_side)[0].price());
|
||||
|
||||
bool market_moved = !securities::is_equal_or_better(other_side, other_side_price, inception_other_side_price);
|
||||
bool on_market = securities::is_same(Price(my_side_psz.price()), Price(algo().price()));
|
||||
if (market_moved || (on_market && my_side_psz.size() <= me->scratch_threshold.value()) )
|
||||
{
|
||||
Price scratch_price = securities::worsen_price(other_side, inception_other_side_price, me->chase_diff);
|
||||
LOG(OrderMan, Diag, "ScratchOrder order {} scratching: {}@{}",
|
||||
algo().order_key().value(), algo().quantity().value(), scratch_price);
|
||||
|
||||
// Time to scratch
|
||||
Update child_update;
|
||||
me->scratch_price = scratch_price;
|
||||
child_update.set_price(scratch_price.value());
|
||||
//we still want to try to scratch all of it
|
||||
child_update.set_quantity(algo().quantity().value());
|
||||
algo().update_child(me->child_key, child_update);
|
||||
me->status = Status::SCRATCHED;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(OrderMan, Diag,
|
||||
"ScratchOrder order {} still waiting to scratch. Order: {}@{} "
|
||||
"My side: {}@{}"
|
||||
"Thresh : {}@{}",
|
||||
algo().order_key().value(), algo().quantity().value(), algo().price().value(),
|
||||
my_side_psz.size(), my_side_psz.price(),
|
||||
me->scratch_threshold.value(), my_quan);
|
||||
}
|
||||
}
|
||||
|
||||
Price ArrivalPriceAlgo::get_price_to_pass (Price price) const
|
||||
{
|
||||
Price rv;
|
||||
switch (me->status) {
|
||||
case Status::WAITING_FOR_MD:
|
||||
case Status::WAITING_TO_SCRATCH:
|
||||
rv = price;
|
||||
break;
|
||||
case Status::SCRATCHED:
|
||||
rv = me->scratch_price;
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void ArrivalPriceAlgo::update_scratch_threshold()
|
||||
{
|
||||
if (algo().definition().custom_def().scratch().scratch_threshold().quantity_case() ==
|
||||
bts::spark::QuantityMeasure::QuantityCase::QUANTITY_NOT_SET)
|
||||
{
|
||||
algo().terminate_error("Invalid quantity, terminating");
|
||||
return;
|
||||
}
|
||||
me->scratch_threshold = SpreaderUtils::_quantity_threshold(
|
||||
algo().definition().custom_def().scratch().scratch_threshold(), algo().quantity());
|
||||
me->chase_diff = Price(securities::tick_size(
|
||||
algo().security()).value() * algo().definition().custom_def().scratch().chase_ticks());
|
||||
}
|
||||
|
||||
void ArrivalPriceAlgo::on_child_change(OrderKey, ChildState const &st)
|
||||
{
|
||||
algo().update_fill_state(st.total_fills, st.last_price);
|
||||
switch (st.status)
|
||||
{
|
||||
case ChildStatus::WORKING:
|
||||
return;
|
||||
case ChildStatus::COMPLETED:
|
||||
algo().complete();
|
||||
return;
|
||||
case ChildStatus::CANCELED:
|
||||
algo().cancel("Unexpected child cancel");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/orderman/orders/algo/IAlgoOrder.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
class ArrivalPriceAlgo : public IAlgoOrder
|
||||
{
|
||||
public:
|
||||
ArrivalPriceAlgo();
|
||||
~ArrivalPriceAlgo();
|
||||
|
||||
OrderOpResult do_before_launch(IBeforeLaunchAlgoServices&) override;
|
||||
void do_launch(IAlgoServices &) override;
|
||||
void do_launch_attached(IAlgoServices&,OrderKey, ChildState) override;
|
||||
void do_update(api::orderman::Update const &) override;
|
||||
void on_book(SecurityKey, Book const &) override;
|
||||
void on_child_change(OrderKey, ChildState const &) override;
|
||||
|
||||
private:
|
||||
enum class Status;
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
IAlgoServices& algo() const;
|
||||
|
||||
void update_scratch_threshold();
|
||||
void try_to_scratch();
|
||||
Price get_price_to_pass (Price price) const;
|
||||
};
|
||||
|
||||
}}
|
||||
@@ -1,227 +0,0 @@
|
||||
#include "lib/orderman/orders/algo/algo_orders/bluex/POVAlgo.h"
|
||||
#include "lib/orderman/orders/algo/IAlgoServices.h"
|
||||
#include "lib/orderman/orders/algo/DynamicHelpers.h"
|
||||
|
||||
#include "lib/orderman/order_factory/IOrderFactory.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderUtils.h"
|
||||
#include "lib/os/os.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
using namespace api::orderman;
|
||||
|
||||
enum class POVAlgo::Status { WAITING_FOR_MD, WAITING_TO_SCRATCH, SCRATCHED };
|
||||
|
||||
struct POVAlgo::PImpl
|
||||
{
|
||||
IAlgoServices *algo;
|
||||
OrderDefinition definition;
|
||||
|
||||
Quantity scratch_threshold;
|
||||
Price chase_diff;
|
||||
Status status = Status::WAITING_FOR_MD;
|
||||
OrderKey child_key = null_order_key();
|
||||
ChildTemplate *child_template = nullptr;
|
||||
Book last_book;
|
||||
Book book_at_inception;
|
||||
Price scratch_price=Price(os::nan());
|
||||
};
|
||||
|
||||
POVAlgo::POVAlgo() : me(new PImpl()) {}
|
||||
POVAlgo::~POVAlgo() {}
|
||||
IAlgoServices &POVAlgo::algo() const { return *me->algo; }
|
||||
|
||||
OrderOpResult POVAlgo::do_before_launch(IBeforeLaunchAlgoServices &serv)
|
||||
{
|
||||
const auto& def = serv.definition();
|
||||
bts_assert(def.has_custom_def());
|
||||
bts_assert(def.custom_def().has_scratch());
|
||||
// Validate the scratch part of the definition
|
||||
auto &scratch = def.custom_def().scratch();
|
||||
if (!scratch.has_child() && OrderKey(def.attach_target_order_key()) == null_order_key())
|
||||
{
|
||||
return OrderOpResult{ ORDER_ERROR_INVALID_ORDER_DEFINITON,
|
||||
"Scratch order must have either a child order definition or an order to attach to"};
|
||||
}
|
||||
if (!serv.is_attaching())
|
||||
{
|
||||
// if we are not attaching create a child template so we can
|
||||
// quickly launch our child when the time comes.
|
||||
auto child_def = def;
|
||||
*child_def.mutable_custom_def() = def.custom_def().scratch().child();
|
||||
me->child_template = &(serv.make_child_template(child_def));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void POVAlgo::do_launch(IAlgoServices &algo)
|
||||
{
|
||||
me->algo = &algo;
|
||||
update_scratch_threshold();
|
||||
bts_assert(me->child_template);
|
||||
me->child_key = algo.launch_child(*me->child_template, algo.price(), algo.quantity());
|
||||
algo.subscribe_book(SecurityKey(algo.security().id()));
|
||||
}
|
||||
|
||||
void POVAlgo::do_launch_attached(IAlgoServices &algo, OrderKey k, ChildState st)
|
||||
{
|
||||
me->algo = &algo;
|
||||
update_scratch_threshold();
|
||||
me->child_key = k;
|
||||
algo.subscribe_book(SecurityKey(algo.security().id()));
|
||||
on_child_change(k, st);
|
||||
}
|
||||
|
||||
void POVAlgo::do_update(api::orderman::Update const &update)
|
||||
{
|
||||
LOG(OrderMan, Diag, "ScratchOrder order {} receiving update: {}", algo().order_key().value(), utils::pb::to_string(update));
|
||||
|
||||
if (update.has_custom() && !update.custom().has_scratch())
|
||||
{
|
||||
algo().terminate_error("Invalid update");
|
||||
return;
|
||||
}
|
||||
|
||||
Update child_update;
|
||||
Price price_to_pass = get_price_to_pass(Price(update.price()));
|
||||
child_update.set_price(price_to_pass.value());
|
||||
child_update.set_quantity(update.quantity());
|
||||
if (update.has_custom())
|
||||
{
|
||||
update_scratch_threshold();
|
||||
auto &scratch_update = update.custom().scratch();
|
||||
*child_update.mutable_custom() = scratch_update.child();
|
||||
}
|
||||
algo().update_child(me->child_key, child_update);
|
||||
|
||||
// If we were not yet scratched it is possible we now can, since we
|
||||
// could have changed the scratch_threshold
|
||||
if (me->status == Status::WAITING_TO_SCRATCH)
|
||||
try_to_scratch();
|
||||
}
|
||||
|
||||
void POVAlgo::on_book(SecurityKey, Book const &b)
|
||||
{
|
||||
me->last_book = b;
|
||||
|
||||
LOG(OrderMan, Diag, "ScratchOrder order {} on book. BID: {}@{} ASK: {}@{}",
|
||||
algo().order_key().value(), b.side(api::SIDE_BUY)[0].size(),
|
||||
b.side(api::SIDE_BUY)[0].price(), b.side(api::SIDE_SELL)[0].size(),
|
||||
b.side(api::SIDE_SELL)[0].price());
|
||||
|
||||
switch (me->status)
|
||||
{
|
||||
case Status::WAITING_FOR_MD:
|
||||
{
|
||||
auto other_side = securities::other_side(algo().definition().side());
|
||||
auto &other_side_top = me->last_book.side(other_side)[0];
|
||||
|
||||
if (other_side_top.size() > 0)
|
||||
{
|
||||
me->status = Status::WAITING_TO_SCRATCH;
|
||||
me->book_at_inception = b;
|
||||
LOG(OrderMan, Diag,
|
||||
"ScratchOrder order {} receiving first book: {} Target: {}",
|
||||
algo().order_key().value(), me->scratch_threshold.value(),
|
||||
other_side_top.price());
|
||||
try_to_scratch();
|
||||
}
|
||||
} break;
|
||||
case Status::SCRATCHED:
|
||||
break;
|
||||
case Status::WAITING_TO_SCRATCH:
|
||||
try_to_scratch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void POVAlgo::try_to_scratch()
|
||||
{
|
||||
bts_assert(me->status == Status::WAITING_TO_SCRATCH);
|
||||
auto my_side = algo().definition().side();
|
||||
auto other_side = securities::other_side(my_side);
|
||||
|
||||
Quantity my_quan;
|
||||
auto &my_side_psz = me->last_book.side(my_side)[0];
|
||||
auto &other_side_psz = me->last_book.side(other_side)[0];
|
||||
auto other_side_price = Price(other_side_psz.price());
|
||||
auto inception_other_side_price = Price(me->book_at_inception.side(other_side)[0].price());
|
||||
|
||||
bool market_moved = !securities::is_equal_or_better(other_side, other_side_price, inception_other_side_price);
|
||||
bool on_market = securities::is_same(Price(my_side_psz.price()), Price(algo().price()));
|
||||
if (market_moved || (on_market && my_side_psz.size() <= me->scratch_threshold.value()) )
|
||||
{
|
||||
Price scratch_price = securities::worsen_price(other_side, inception_other_side_price, me->chase_diff);
|
||||
LOG(OrderMan, Diag, "ScratchOrder order {} scratching: {}@{}",
|
||||
algo().order_key().value(), algo().quantity().value(), scratch_price);
|
||||
|
||||
// Time to scratch
|
||||
Update child_update;
|
||||
me->scratch_price = scratch_price;
|
||||
child_update.set_price(scratch_price.value());
|
||||
//we still want to try to scratch all of it
|
||||
child_update.set_quantity(algo().quantity().value());
|
||||
algo().update_child(me->child_key, child_update);
|
||||
me->status = Status::SCRATCHED;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(OrderMan, Diag,
|
||||
"ScratchOrder order {} still waiting to scratch. Order: {}@{} "
|
||||
"My side: {}@{}"
|
||||
"Thresh : {}@{}",
|
||||
algo().order_key().value(), algo().quantity().value(), algo().price().value(),
|
||||
my_side_psz.size(), my_side_psz.price(),
|
||||
me->scratch_threshold.value(), my_quan);
|
||||
}
|
||||
}
|
||||
|
||||
Price POVAlgo::get_price_to_pass (Price price) const
|
||||
{
|
||||
Price rv;
|
||||
switch (me->status) {
|
||||
case Status::WAITING_FOR_MD:
|
||||
case Status::WAITING_TO_SCRATCH:
|
||||
rv = price;
|
||||
break;
|
||||
case Status::SCRATCHED:
|
||||
rv = me->scratch_price;
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void POVAlgo::update_scratch_threshold()
|
||||
{
|
||||
if (algo().definition().custom_def().scratch().scratch_threshold().quantity_case() ==
|
||||
bts::spark::QuantityMeasure::QuantityCase::QUANTITY_NOT_SET)
|
||||
{
|
||||
algo().terminate_error("Invalid quantity, terminating");
|
||||
return;
|
||||
}
|
||||
me->scratch_threshold = SpreaderUtils::_quantity_threshold(
|
||||
algo().definition().custom_def().scratch().scratch_threshold(), algo().quantity());
|
||||
me->chase_diff = Price(securities::tick_size(
|
||||
algo().security()).value() * algo().definition().custom_def().scratch().chase_ticks());
|
||||
}
|
||||
|
||||
void POVAlgo::on_child_change(OrderKey, ChildState const &st)
|
||||
{
|
||||
algo().update_fill_state(st.total_fills, st.last_price);
|
||||
switch (st.status)
|
||||
{
|
||||
case ChildStatus::WORKING:
|
||||
return;
|
||||
case ChildStatus::COMPLETED:
|
||||
algo().complete();
|
||||
return;
|
||||
case ChildStatus::CANCELED:
|
||||
algo().cancel("Unexpected child cancel");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/orderman/orders/algo/IAlgoOrder.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
class POVAlgo : public IAlgoOrder
|
||||
{
|
||||
public:
|
||||
POVAlgo();
|
||||
~POVAlgo();
|
||||
|
||||
OrderOpResult do_before_launch(IBeforeLaunchAlgoServices&) override;
|
||||
void do_launch(IAlgoServices &) override;
|
||||
void do_launch_attached(IAlgoServices&,OrderKey, ChildState) override;
|
||||
void do_update(api::orderman::Update const &) override;
|
||||
void on_book(SecurityKey, Book const &) override;
|
||||
void on_child_change(OrderKey, ChildState const &) override;
|
||||
|
||||
private:
|
||||
enum class Status;
|
||||
struct PImpl;
|
||||
std::unique_ptr<PImpl> me;
|
||||
IAlgoServices& algo() const;
|
||||
|
||||
void update_scratch_threshold();
|
||||
void try_to_scratch();
|
||||
Price get_price_to_pass (Price price) const;
|
||||
};
|
||||
|
||||
}}
|
||||
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user