Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
469ee033b2 | ||
|
|
451fb67195 | ||
|
|
a21739a866 | ||
|
|
7d694f5c04 | ||
|
|
14e08cf508 | ||
|
|
12349ef8b7 |
No files matched your search
@@ -22,4 +22,5 @@ node_modules
|
||||
paket-files
|
||||
project.lock.json
|
||||
src/server/sparkd/orderman/perf_analysis/data
|
||||
src/server/sparkd/orderman/perf_analysis/logs/
|
||||
src/server/sparkd/orderman/perf_analysis/trace_data/
|
||||
@@ -134,7 +134,9 @@ namespace bts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (neworder, oldorder) in update.changes) {
|
||||
foreach (var order in update.changes) {
|
||||
var neworder = order.New;
|
||||
var oldorder = order.Old;
|
||||
(var security, var spec) = get_security(neworder.Def.SecurityKey);
|
||||
//
|
||||
// description
|
||||
|
||||
@@ -24,13 +24,15 @@ namespace mbts.spark
|
||||
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<CustomOneofCase>>(child_order_types, true);
|
||||
cross_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
|
||||
new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1}, false);
|
||||
max_chase_ticks = new InlineUserProperty<uint>(10, false);
|
||||
max_chase_ticks = new InlineUserProperty<uint>(2, false);
|
||||
detach_on_toward = new InlineUserProperty<bool>(true, false);
|
||||
}
|
||||
public readonly InlineUserProperty<CustomOneofCase> selected_child_order_type;
|
||||
public readonly InlineUserProperty<IReadOnlyCollection<CustomOneofCase>> child_order_types;
|
||||
|
||||
public readonly InlineUserProperty<bts.spark.QuantityMeasure> cross_threshold;
|
||||
public readonly InlineUserProperty<uint> max_chase_ticks;
|
||||
public readonly InlineUserProperty<bool> detach_on_toward;
|
||||
}
|
||||
|
||||
class LeanOrderVM : OrderTypeVMBase<LeanOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
|
||||
@@ -44,7 +46,8 @@ namespace mbts.spark
|
||||
IDisposable _dispose, _child_order_errors_sub;
|
||||
|
||||
public bts.spark.QuantityMeasure cross_threshold { get; set; } = new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1 };
|
||||
public uint max_chase_ticks { get; set; } = 10;
|
||||
public uint max_chase_ticks { get; set; } = 2;
|
||||
public bool detach_on_toward { get; set; } = true;
|
||||
|
||||
public LeanOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source)
|
||||
: this(model, security_md_source, security_md_source.Select(smd =>
|
||||
@@ -77,6 +80,11 @@ namespace mbts.spark
|
||||
max_chase_ticks = p.max_chase_ticks.value;
|
||||
RaisePropertyChanged(nameof(max_chase_ticks));
|
||||
}
|
||||
if (p.detach_on_toward.force_override)
|
||||
{
|
||||
detach_on_toward = p.detach_on_toward.value;
|
||||
RaisePropertyChanged(nameof(detach_on_toward));
|
||||
}
|
||||
_inline_props = p;
|
||||
_validate();
|
||||
})
|
||||
@@ -94,6 +102,7 @@ namespace mbts.spark
|
||||
var i = factory.lean_order();
|
||||
i.CrossThreshold = cross_threshold;
|
||||
i.MaxChaseTicks = max_chase_ticks;
|
||||
i.DetachOnToward = detach_on_toward;
|
||||
child_order.assign_to(i.Child);
|
||||
value.Lean = i;
|
||||
}
|
||||
|
||||
@@ -222,6 +222,8 @@
|
||||
<RowDefinition Height="4" />
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="4" />
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="4" />
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -233,9 +235,10 @@
|
||||
<uag:QuantityMeasureControl Grid.Row="1" Grid.Column="2" QuantityMeasure="{Binding cross_threshold}"/>
|
||||
<TextBlock Grid.Row="3" VerticalAlignment="Center">Max Chase Ticks</TextBlock>
|
||||
<c:TickUpDownUInt Grid.Row="3" Grid.Column="2" Value="{Binding max_chase_ticks}"/>
|
||||
<TextBlock Grid.Row="5">Child</TextBlock>
|
||||
<CheckBox Grid.Row="5" Grid.Column="2" VerticalAlignment="Center" Margin="0,0,0,0" IsChecked="{Binding detach_on_toward}">Detach on Toward</CheckBox>
|
||||
<TextBlock Grid.Row="7">Child</TextBlock>
|
||||
<uag:OrderDetailsPopupControl
|
||||
Grid.Row="5" Grid.Column="2"
|
||||
Grid.Row="7" Grid.Column="2"
|
||||
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
|
||||
ItemsSource="{Binding child_order_types}"
|
||||
SelectedItem="{Binding child_order}"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
@@ -53,28 +54,43 @@ namespace bts.api.core {
|
||||
#endif
|
||||
}
|
||||
|
||||
public readonly struct Change<T> {
|
||||
public Change(T o, T n) {
|
||||
Old = o;
|
||||
New = n;
|
||||
}
|
||||
public readonly T Old;
|
||||
public readonly T New;
|
||||
public Change<T> merge(Change<T> newer) {
|
||||
return new Change<T>(Old, newer.New);
|
||||
}
|
||||
public override string ToString() {
|
||||
return $"{{{Old}=>{New}}}";
|
||||
}
|
||||
}
|
||||
|
||||
public class Update<T, TKey> where TKey : IEquatable<TKey> {
|
||||
private Func<T, TKey> _key;
|
||||
internal Update(
|
||||
IReadOnlyCollection<T> all,
|
||||
IEnumerable<T> added,
|
||||
IEnumerable<(T New,T Old)> changes,
|
||||
IEnumerable<Change<T>> changes,
|
||||
IEnumerable<T> removed,
|
||||
Func<T, TKey> key_extractor) {
|
||||
this.added = added ?? new T[0];
|
||||
this.removed = removed ?? new T[0];
|
||||
this.changes = changes ?? new (T,T)[0];
|
||||
this.changes = changes ?? new Change<T>[0];
|
||||
this.all = all;
|
||||
_key = key_extractor;
|
||||
}
|
||||
|
||||
public static Update<T, TKey> empty(Func<T, TKey> key_extractor) =>
|
||||
new Update<T, TKey>(new T[0], new T[0], new (T,T)[0], new T[0], key_extractor);
|
||||
new Update<T, TKey>(new T[0], new T[0], new Change<T>[0], new T[0], key_extractor);
|
||||
|
||||
public Update<T,TKey> merge(Update<T, TKey> next) {
|
||||
var comp = new RowEqualityComparer<T, TKey>(_key);
|
||||
var added = this.added as HashSet<T> ?? new HashSet<T>(this.added, comp);
|
||||
var changes = this.changed as HashSet<(T New,T Old)> ?? new HashSet<(T,T)>(this.changes, comp);
|
||||
var changes = this.changed as ChangeDict<T,TKey> ?? new ChangeDict<T,TKey>(this.changes, _key);
|
||||
var removed = this.removed as HashSet<T> ?? new HashSet<T>(this.removed, comp);
|
||||
|
||||
// Add
|
||||
@@ -87,9 +103,7 @@ namespace bts.api.core {
|
||||
added.Add(c.New);
|
||||
}
|
||||
else {
|
||||
// Remove does not error if it was not present
|
||||
changes.Remove(c);
|
||||
changes.Add(c);
|
||||
changes.AddOrMerge(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +112,7 @@ namespace bts.api.core {
|
||||
if (!added.Remove(r)) {
|
||||
removed.Add(r);
|
||||
}
|
||||
changes.Remove((r,r));
|
||||
changes.Remove(_key(r));
|
||||
}
|
||||
|
||||
return new Update<T, TKey>(
|
||||
@@ -110,7 +124,7 @@ namespace bts.api.core {
|
||||
|
||||
public IReadOnlyCollection<T> all { get; }
|
||||
public IEnumerable<T> added { get; }
|
||||
public IEnumerable<(T New,T Old)> changes { get; }
|
||||
public IEnumerable<Change<T>> changes { get; }
|
||||
public IEnumerable<T> changed => changes.Select(c => c.New);
|
||||
public IEnumerable<T> removed { get; }
|
||||
|
||||
@@ -127,7 +141,40 @@ namespace bts.api.core {
|
||||
#endif
|
||||
}
|
||||
|
||||
struct RowEqualityComparer<T,TKey> : IEqualityComparer<T>, IEqualityComparer<(T,T)>
|
||||
class ChangeDict<T, TKey> : IEnumerable<Change<T>> {
|
||||
Dictionary<TKey, Change<T>> _changes;
|
||||
Func<Change<T>, TKey> _key;
|
||||
|
||||
public ChangeDict(IEnumerable<Change<T>> changes, Func<T, TKey> key) {
|
||||
_key = x => key(x.New);
|
||||
_changes = changes.ToDictionary(_key);
|
||||
}
|
||||
|
||||
public Change<T>? AddOrMerge(Change<T> newer) {
|
||||
var key = _key(newer);
|
||||
if (_changes.TryGetValue(key, out Change<T> old)) {
|
||||
_changes[key] = old.merge(newer);
|
||||
return old;
|
||||
}
|
||||
_changes.Add(key, newer);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Remove(TKey key) {
|
||||
_changes.Remove(key);
|
||||
}
|
||||
|
||||
#region IEnumerable
|
||||
public IEnumerator<Change<T>> GetEnumerator() {
|
||||
return _changes.Values.GetEnumerator();
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return _changes.Values.GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
struct RowEqualityComparer<T,TKey> : IEqualityComparer<T>, IEqualityComparer<Change<T>>
|
||||
where TKey : IEquatable<TKey> {
|
||||
readonly Func<T,TKey> _key;
|
||||
|
||||
@@ -139,16 +186,16 @@ namespace bts.api.core {
|
||||
return _key(x).Equals(_key(y));
|
||||
}
|
||||
|
||||
public bool Equals((T, T) x, (T, T) y) {
|
||||
return Equals(x.Item1, y.Item1);
|
||||
public bool Equals(Change<T> x, Change<T> y) {
|
||||
return Equals(x.New, y.New);
|
||||
}
|
||||
|
||||
public int GetHashCode(T obj) {
|
||||
return _key(obj).GetHashCode();
|
||||
}
|
||||
|
||||
public int GetHashCode((T, T) obj) {
|
||||
return GetHashCode(obj.Item1);
|
||||
public int GetHashCode(Change<T> c) {
|
||||
return GetHashCode(c.New);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +206,7 @@ namespace bts.api.core {
|
||||
internal TableUpdate(
|
||||
ImmutableDictionary<TKey, T> init,
|
||||
IEnumerable<T> added,
|
||||
IEnumerable<(T,T)> changed,
|
||||
IEnumerable<Change<T>> changed,
|
||||
IEnumerable<T> removed) {
|
||||
_state = init;
|
||||
this.added = added;
|
||||
@@ -169,7 +216,7 @@ namespace bts.api.core {
|
||||
|
||||
public IReadOnlyDictionary<TKey, T> state { get { return _state; } }
|
||||
public IEnumerable<T> added { get; }
|
||||
public IEnumerable<(T New,T Old)> changes { get; }
|
||||
public IEnumerable<Change<T>> changes { get; }
|
||||
public IEnumerable<T> changed => changes.Select(c => c.New);
|
||||
|
||||
public IEnumerable<T> removed { get; }
|
||||
@@ -185,7 +232,7 @@ namespace bts.api.core {
|
||||
}
|
||||
|
||||
internal TableUpdate<T, TKey> as_snapshot() {
|
||||
return new TableUpdate<T, TKey>(_state, _state.Values.ToList(), new (T,T)[0], new T[0]);
|
||||
return new TableUpdate<T, TKey>(_state, _state.Values.ToList(), new Change<T>[0], new T[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +255,7 @@ namespace bts.api.core {
|
||||
if (raw.is_reset) {
|
||||
var removed = state.Values.ToList();
|
||||
state.Clear();
|
||||
return new Update<T, TKey>(new T[0], new T[0], new (T,T)[0], removed, key_extractor);
|
||||
return new Update<T, TKey>(new T[0], new T[0], new Change<T>[0], removed, key_extractor);
|
||||
}
|
||||
else {
|
||||
var removed = new List<T>(raw.removed_keys.Count);
|
||||
@@ -222,11 +269,11 @@ namespace bts.api.core {
|
||||
for (int x = 0; x < raw.added_items.Count; ++x) {
|
||||
state[raw.added_keys[x]] = raw.added_items[x];
|
||||
}
|
||||
List<(T, T)> changes = new List<(T, T)>(raw.changed_items.Count);
|
||||
var changes = new List<Change<T>>(raw.changed_items.Count);
|
||||
for (int x = 0; x < raw.changed_items.Count; ++x) {
|
||||
var old = state[raw.changed_keys[x]];
|
||||
state[raw.changed_keys[x]] = raw.changed_items[x];
|
||||
changes.Add((raw.changed_items[x], old));
|
||||
changes.Add(new Change<T>(old, raw.changed_items[x]));
|
||||
}
|
||||
return new Update<T, TKey>(state.Values.ToList(), raw.added_items.ToList(), changes, removed, key_extractor);
|
||||
}
|
||||
@@ -235,7 +282,7 @@ namespace bts.api.core {
|
||||
|
||||
public static IObservable<TableUpdate<T,TKey>> Table<T,TKey>(this IObservable<Update<T,TKey>> source) where TKey : IEquatable<TKey> =>
|
||||
source.Scan(
|
||||
new TableUpdate<T,TKey>(ImmutableDictionary<TKey,T>.Empty, new T[0], new (T,T)[0], new T[0]),
|
||||
new TableUpdate<T,TKey>(ImmutableDictionary<TKey,T>.Empty, new T[0], new Change<T>[0], new T[0]),
|
||||
(table, update) => TableUpdate<T,TKey>.update(table,update));
|
||||
|
||||
// Fold updates and emit at max 1/interval
|
||||
|
||||
@@ -227,5 +227,15 @@ namespace mbts.api.Test {
|
||||
await validate_naggle(raw);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void test_merge_begin_end_state() {
|
||||
int key(string s) => s[0];
|
||||
var empty = new string[0];
|
||||
var a2 = new Update<string, int>(new[] { "a2" }, empty, new[] { new Change<string>("a1", "a2") }, empty, key);
|
||||
var a3 = new Update<string, int>(new[] { "a3" }, empty, new[] { new Change<string>("a2", "a3") }, empty, key);
|
||||
var merged = a2.merge(a3);
|
||||
Assert.SequenceEqual(new[] { new Change<string>("a1", "a3") }, merged.changes);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -109,6 +109,7 @@ message TickOrderDefinition {
|
||||
message LeanOrderDefinition {
|
||||
spark.QuantityMeasure cross_threshold = 1;
|
||||
uint32 max_chase_ticks = 2;
|
||||
bool detach_on_toward = 4;
|
||||
CustomOrderDefinition child = 3;
|
||||
}
|
||||
message JoinOrderDefinition {
|
||||
|
||||
@@ -132,7 +132,7 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size,
|
||||
"perf_event:tick_to_order s2s_us:{} fix_socket_r:{} md:{} "
|
||||
"md_src:{} spreader_on_book:{} spreader_modify_order:{} "
|
||||
"spreader_on_child_order_update:{} "
|
||||
"order_update:{} exe_gw:{} fix_socket_w:{} md_sn:{}",
|
||||
"order_update:{} exe_gw:{} fix_socket_w:{} md_sn:{} order_key:{}",
|
||||
s2s.microseconds(), trace_cpy.fix_socket_r.to_uint64(),
|
||||
trace_cpy.md.to_uint64(), trace_cpy.md_src.to_uint64(),
|
||||
trace_cpy.spreader_on_book.to_uint64(),
|
||||
@@ -140,7 +140,8 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size,
|
||||
trace_cpy.spreader_on_child_order_update.to_uint64(),
|
||||
trace_cpy.order_update.to_uint64(),
|
||||
trace_cpy.exe_gw.to_uint64(), trace_cpy.fix_socket_w.to_uint64(),
|
||||
trace_cpy.md_sn);
|
||||
trace_cpy.md_sn,
|
||||
trace_cpy.order_key);
|
||||
_tick_to_order->observe(s2s.nanoseconds());
|
||||
}
|
||||
|
||||
@@ -150,7 +151,7 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size,
|
||||
"perf_event:fill_to_order s2s_us:{} fix_socket_r:{} md:{} md_src:{} "
|
||||
"spreader_on_book:{} spreader_modify_order:{} "
|
||||
"spreader_on_child_order_update:{} "
|
||||
"order_update:{} exe_gw:{} fix_socket_w:{} md_sn:{}",
|
||||
"order_update:{} exe_gw:{} fix_socket_w:{} md_sn:{} order_key:{}",
|
||||
s2s.microseconds(), trace_cpy.fix_socket_r.to_uint64(),
|
||||
trace_cpy.md.to_uint64(), trace_cpy.md_src.to_uint64(),
|
||||
trace_cpy.spreader_on_book.to_uint64(),
|
||||
@@ -158,7 +159,8 @@ int SocketConnection::write(WriteVec const &vec, size_t vec_size,
|
||||
trace_cpy.spreader_on_child_order_update.to_uint64(),
|
||||
trace_cpy.order_update.to_uint64(),
|
||||
trace_cpy.exe_gw.to_uint64(), trace_cpy.fix_socket_w.to_uint64(),
|
||||
trace_cpy.md_sn);
|
||||
trace_cpy.md_sn,
|
||||
trace.order_key);
|
||||
_fill_to_order->observe(s2s.nanoseconds());
|
||||
}
|
||||
|
||||
|
||||
@@ -76,8 +76,7 @@ string dump_security(const FixedSecurity& security) {
|
||||
res << "'main_frac': " << (int)security.cme_main_fraction << ", ";
|
||||
res << "'sub_fract': " << (int)security.cme_sub_fraction << ", ";
|
||||
res << "'price_format': " << (int)security.cme_price_display_format << ", ";
|
||||
|
||||
res << "'market_segment': " << security.cme_market_segment_id << ", ";
|
||||
res << "'market_segment': " << (int)security.cme_market_segment_id << ", ";
|
||||
|
||||
res << "'price_break': " << security.price_break << ", ";
|
||||
res << "'low_tick': " << security.low_tick << ", ";
|
||||
|
||||
@@ -16,6 +16,7 @@ public:
|
||||
utils::TimeStamp exe_gw ;
|
||||
utils::TimeStamp fix_socket_w ;
|
||||
utils::TimeStamp spreader_modify_order ;
|
||||
uint32_t order_key = 0;
|
||||
uint16_t md_sn = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -271,7 +271,10 @@ NativeOrder::~NativeOrder() {}
|
||||
|
||||
void NativeOrder::on_activate(Price p, Quantity q,
|
||||
bts::orderman::OrderServices &services,
|
||||
PerfTrace const&trace) {
|
||||
PerfTrace const&t) {
|
||||
auto trace = t;
|
||||
trace.order_key = key().value();
|
||||
|
||||
tracepoint(bts_trace, trace_order, (char *)"on_activate", 0, trace.md_sn, 0);
|
||||
bts_assert(!me->services);
|
||||
me->services = &services;
|
||||
@@ -454,6 +457,7 @@ void NativeOrder::on_activate(Price p, Quantity q,
|
||||
void NativeOrder::on_update(Price p, Quantity q, PerfTrace const &t) {
|
||||
auto trace = t;
|
||||
trace.order_update = utils::TimeStamp::now();
|
||||
trace.order_key = key().value();
|
||||
tracepoint(bts_trace, trace_order, (char *)"on_update", 0, trace.md_sn, 0);
|
||||
|
||||
switch (me->state.status()) {
|
||||
|
||||
@@ -408,14 +408,14 @@ void BookAlgo::report_state()
|
||||
me->services->report_state(merged_state);
|
||||
}
|
||||
|
||||
void BookAlgo::payup(const md::PriceSize& opposite, uint32_t cross_ticks)
|
||||
void BookAlgo::payup(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks)
|
||||
{
|
||||
double new_price = opposite.price() + me->tick_size * cross_ticks;
|
||||
me->child.update(Price(new_price), Quantity(this_state().quantity()));
|
||||
report_state();
|
||||
}
|
||||
|
||||
void BookAlgo::paydown(const md::PriceSize& opposite, uint32_t cross_ticks)
|
||||
void BookAlgo::paydown(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks)
|
||||
{
|
||||
double new_price = opposite.price() - me->tick_size * cross_ticks;
|
||||
me->child.update(Price(new_price), Quantity(this_state().quantity()));
|
||||
|
||||
@@ -42,8 +42,8 @@ protected:
|
||||
virtual void transition(api::orderman::OrderStatus new_state, std::string = "");
|
||||
virtual void report_state();
|
||||
|
||||
virtual void payup(const md::PriceSize&, uint32_t cross_ticks = 0);
|
||||
virtual void paydown(const md::PriceSize&, uint32_t cross_ticks = 0);
|
||||
virtual void payup(const md::PriceSize&, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks = 0);
|
||||
virtual void paydown(const md::PriceSize&, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks = 0);
|
||||
void detach(bts::api::orderman::OrderStatus status_after_detach = bts::api::orderman::ORDER_STATUS_CANCELED);
|
||||
private:
|
||||
struct PImpl;
|
||||
|
||||
@@ -12,12 +12,15 @@ using namespace api::orderman;
|
||||
|
||||
struct LeanOrder::PImpl
|
||||
{
|
||||
PImpl() {}
|
||||
PImpl() : cross_threshold(), max_chase_ticks(0), detach_on_toward(false), opposite_at_inception(), num_chases(0)
|
||||
{}
|
||||
|
||||
spark::QuantityMeasure cross_threshold;
|
||||
uint32_t max_chase_ticks;
|
||||
bool detach_on_toward;
|
||||
|
||||
md::PriceSize opposite_at_inception;
|
||||
uint32_t num_chases;
|
||||
};
|
||||
|
||||
|
||||
@@ -34,25 +37,40 @@ void LeanOrder::setup_child(const api::orderman::OrderDefinition& this_def, cons
|
||||
|
||||
me->cross_threshold = lean_def.cross_threshold();
|
||||
me->max_chase_ticks = lean_def.max_chase_ticks();
|
||||
me->detach_on_toward = lean_def.detach_on_toward();
|
||||
}
|
||||
|
||||
void LeanOrder::payup(const md::PriceSize& opposite, uint32_t cross_ticks)
|
||||
void LeanOrder::payup(const md::PriceSize&, const bts::orderman::BookUpdateEvent& book, uint32_t cross_ticks /*= 0*/)
|
||||
{
|
||||
double new_price = opposite.price() + tick_size() * cross_ticks;
|
||||
double new_price = me->opposite_at_inception.price() + tick_size() * cross_ticks;
|
||||
double limit = me->opposite_at_inception.price() + tick_size() * me->max_chase_ticks;
|
||||
if(new_price <= limit)
|
||||
update_child(Price(new_price), Quantity(this_state().quantity()));
|
||||
else
|
||||
{
|
||||
update_child(Price(limit), Quantity(this_state().quantity()));
|
||||
update_child(Price(limit), Quantity(this_state().quantity()));
|
||||
detach();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const bts::orderman::BookSide& sellbook = book.book.side(api::Side::SIDE_SELL);
|
||||
for(const auto& i : sellbook)
|
||||
{
|
||||
me->opposite_at_inception = i;
|
||||
if(me->opposite_at_inception.price() > new_price)
|
||||
break;
|
||||
}
|
||||
if(me->opposite_at_inception.price() <= new_price)
|
||||
detach();
|
||||
me->num_chases += cross_ticks+1;
|
||||
if(me->num_chases >= me->max_chase_ticks)
|
||||
detach();
|
||||
report_state();
|
||||
}
|
||||
|
||||
void LeanOrder::paydown(const md::PriceSize& opposite, uint32_t cross_ticks)
|
||||
void LeanOrder::paydown(const md::PriceSize&, const bts::orderman::BookUpdateEvent& book, uint32_t cross_ticks /*= 0*/)
|
||||
{
|
||||
double new_price = opposite.price() - tick_size() * cross_ticks;
|
||||
double new_price = me->opposite_at_inception.price() - tick_size() * cross_ticks;
|
||||
double limit = me->opposite_at_inception.price() - tick_size() * me->max_chase_ticks;
|
||||
if(new_price >= limit)
|
||||
update_child(Price(new_price), Quantity(this_state().quantity()));
|
||||
@@ -60,11 +78,24 @@ void LeanOrder::paydown(const md::PriceSize& opposite, uint32_t cross_ticks)
|
||||
{
|
||||
update_child(Price(limit), Quantity(this_state().quantity()));
|
||||
detach();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const bts::orderman::BookSide& buybook = book.book.side(api::Side::SIDE_BUY);
|
||||
for(const auto& i : buybook)
|
||||
{
|
||||
me->opposite_at_inception = i;
|
||||
if(me->opposite_at_inception.price() < new_price)
|
||||
break;
|
||||
}
|
||||
if(me->opposite_at_inception.price() >= new_price)
|
||||
detach();
|
||||
me->num_chases += cross_ticks+1;
|
||||
if(me->num_chases >= me->max_chase_ticks)
|
||||
detach();
|
||||
report_state();
|
||||
}
|
||||
|
||||
|
||||
void LeanOrder::on_book_update(const bts::orderman::BookUpdateEvent& book)
|
||||
{
|
||||
switch (this_state().status())
|
||||
@@ -91,26 +122,36 @@ void LeanOrder::on_book_update(const bts::orderman::BookUpdateEvent& book)
|
||||
{
|
||||
const auto& opposite = book.book.side(api::Side::SIDE_SELL)[0];
|
||||
if(opposite.price() < me->opposite_at_inception.price())
|
||||
me->opposite_at_inception = opposite; //your lucky day, try to get luckier
|
||||
{
|
||||
if(me->detach_on_toward)
|
||||
detach();
|
||||
else
|
||||
me->opposite_at_inception = opposite; //we don't want to detach so look at next level
|
||||
}
|
||||
else if(opposite.price() > me->opposite_at_inception.price())
|
||||
payup(opposite); //you missed, payup
|
||||
payup(opposite, book); //you missed, payup/join
|
||||
else
|
||||
{
|
||||
if(opposite.size() <= thresh.value())
|
||||
payup(opposite);
|
||||
payup(opposite, book);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& opposite = book.book.side(api::Side::SIDE_BUY)[0];
|
||||
if(opposite.price() > me->opposite_at_inception.price())
|
||||
me->opposite_at_inception = opposite;
|
||||
{
|
||||
if(me->detach_on_toward)
|
||||
detach();
|
||||
else
|
||||
me->opposite_at_inception = opposite;
|
||||
}
|
||||
else if(opposite.price() < me->opposite_at_inception.price())
|
||||
paydown(opposite);
|
||||
paydown(opposite, book);
|
||||
else
|
||||
{
|
||||
if(opposite.size() <= thresh.value())
|
||||
paydown(opposite);
|
||||
paydown(opposite, book);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ protected:
|
||||
api::orderman::OrderState&, api::orderman::OrderDefinition*) override;
|
||||
void on_book_update(const bts::orderman::BookUpdateEvent&) override;
|
||||
private:
|
||||
void payup(const md::PriceSize& opposite, uint32_t cross_ticks = 0) override;
|
||||
void paydown(const md::PriceSize& opposite, uint32_t cross_ticks = 0) override;
|
||||
void payup(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks = 0) override;
|
||||
void paydown(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks = 0) override;
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
|
||||
@@ -43,7 +43,7 @@ void TickOrder::setup_child(const api::orderman::OrderDefinition& this_def, cons
|
||||
me->detach_on_toward = tick_def.detach_on_toward();
|
||||
}
|
||||
|
||||
void TickOrder::payup(const md::PriceSize& opposite, uint32_t cross_ticks)
|
||||
void TickOrder::payup(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks)
|
||||
{
|
||||
double new_price = opposite.price() + tick_size() * cross_ticks;
|
||||
double limit = me->opposite_at_inception.price() + tick_size() * me->max_chase_ticks;
|
||||
@@ -57,7 +57,7 @@ void TickOrder::payup(const md::PriceSize& opposite, uint32_t cross_ticks)
|
||||
report_state();
|
||||
}
|
||||
|
||||
void TickOrder::paydown(const md::PriceSize& opposite, uint32_t cross_ticks)
|
||||
void TickOrder::paydown(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks)
|
||||
{
|
||||
double new_price = opposite.price() - tick_size() * cross_ticks;
|
||||
double limit = me->opposite_at_inception.price() - tick_size() * me->max_chase_ticks;
|
||||
@@ -127,11 +127,11 @@ void TickOrder::on_book_update(const bts::orderman::BookUpdateEvent& book)
|
||||
me->opposite_at_inception = opposite;
|
||||
}
|
||||
else if(opposite.price() > me->opposite_at_inception.price())
|
||||
payup(opposite, me->cross_ticks);
|
||||
payup(opposite, book, me->cross_ticks);
|
||||
else
|
||||
{
|
||||
if(opposite.size() <= thresh.value())
|
||||
payup(opposite, me->cross_ticks);
|
||||
payup(opposite, book, me->cross_ticks);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -145,11 +145,11 @@ void TickOrder::on_book_update(const bts::orderman::BookUpdateEvent& book)
|
||||
me->opposite_at_inception = opposite;
|
||||
}
|
||||
else if(opposite.price() < me->opposite_at_inception.price())
|
||||
paydown(opposite, me->cross_ticks);
|
||||
paydown(opposite, book, me->cross_ticks);
|
||||
else
|
||||
{
|
||||
if(opposite.size() <= thresh.value())
|
||||
paydown(opposite, me->cross_ticks);
|
||||
paydown(opposite, book, me->cross_ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ protected:
|
||||
api::orderman::OrderState&, api::orderman::OrderDefinition*) override;
|
||||
void on_book_update(const bts::orderman::BookUpdateEvent&) override;
|
||||
private:
|
||||
void payup(const md::PriceSize& opposite, uint32_t cross_ticks) override;
|
||||
void paydown(const md::PriceSize& opposite, uint32_t cross_ticks) override;
|
||||
void payup(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks) override;
|
||||
void paydown(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks) override;
|
||||
|
||||
private:
|
||||
struct PImpl;
|
||||
|
||||
@@ -12,6 +12,7 @@ def gen_create_table(d,t):
|
||||
print ".import %s trace" % t
|
||||
print '''create view tick_to_order as select
|
||||
event_id,
|
||||
order_key,
|
||||
(fix_socket_w - md) / 1000 total,
|
||||
(md_src-md)/1000 md_to_md_src,
|
||||
(spreader_on_book-md_src)/1000 md_src_to_spreader,
|
||||
|
||||
Reference in new issue
Block a user