Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d24becd052 | ||
|
|
13251f5c06 | ||
|
|
03b9aaa0e8 | ||
|
|
32d127fd84 |
No files matched your search
@@ -70,7 +70,7 @@ namespace mbts.analytics {
|
||||
}
|
||||
|
||||
public void set_vol_data(VolSurfaceInput vs_input) {
|
||||
Log.Gen.info($"VolSurfaceInterpGreeksProducer.set_vol_data vs_id: {_vs_id}");
|
||||
Log.Gen.info($"VolSurfaceInterpGreeksProducer.set_vol_data vs_id: {_vs_id} precomputed_theo_handles?: {string.Join(", ", (vs_input?.surface_settings?.advanced_settings?.precomputed_theo_handles).empty_if_null())}");
|
||||
_vs_input = vs_input != null ? VolSurfaceUtilityFunctions.clone_proto(vs_input) : null;
|
||||
_compute_and_fire(InputType.Vol);
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace mbts.spark {
|
||||
length = _initial_row_count,
|
||||
};
|
||||
LadderPriceList _pending_price_list = null;
|
||||
IComparer<double> _price_comparer;
|
||||
IComparer<double> _price_comparer = MathUtils.epsilon_comparer.reverse();
|
||||
double _last_origin_price;
|
||||
readonly MarketBreakLines _mkt_break_lines;
|
||||
NativePriceSize _last_trade;
|
||||
|
||||
@@ -14,6 +14,9 @@ namespace mbts.spark {
|
||||
uint _bid_size, _ask_size;
|
||||
ulong _time;
|
||||
|
||||
public BBOVM() =>
|
||||
_dispose = Disposable.Create(() => Disposable.dispose(ref _md_poll));
|
||||
|
||||
public SecurityImmutable? security => _security_md?.security;
|
||||
public SecurityMD? security_md {
|
||||
get => _security_md;
|
||||
|
||||
@@ -63,7 +63,11 @@ namespace mbts {
|
||||
if (ticks_per_base.is_int()) {
|
||||
return true;
|
||||
}
|
||||
return tick.tick_unit > tick.tick_base && tick.tick_base == 1;
|
||||
// The Log10 check accounts for [non-perp] futures at Deribit, which use TickFactors 25/10
|
||||
// (e.g., 10.0, 12.5, 15.0, etc.). It was added 11/02/2023, when it replaced the
|
||||
// commented out line below.
|
||||
// return tick.tick_unit > tick.tick_base && tick.tick_base == 1;
|
||||
return tick.tick_unit > tick.tick_base && Math.Log10(tick.tick_base).is_int();
|
||||
}
|
||||
|
||||
public static bool is_valid(this RegionalTickFactors regional_tick) =>
|
||||
@@ -667,7 +671,8 @@ namespace mbts {
|
||||
if (negate) {
|
||||
value = -value;
|
||||
}
|
||||
var text = core_impl();
|
||||
var text = tick.tick_unit == 25 && tick.tick_base == 10 ?
|
||||
deribit_future_impl() : core_impl();
|
||||
if (!settings.show_zero_integer) {
|
||||
// Hide the integer if its zero. This could be better optimized,
|
||||
// but speed shouldn't be an issue, so it doesn't seem worth the time/effort.
|
||||
@@ -721,6 +726,37 @@ namespace mbts {
|
||||
return "Overflow";
|
||||
}
|
||||
}
|
||||
|
||||
string deribit_future_impl() {
|
||||
try {
|
||||
// TODO: Replace this hack with a suitable long term solution
|
||||
//
|
||||
// The hack: [non-perp] futures at Deribit tick in units of '2.5' (e.g., 10.0, 12.5,
|
||||
// 15.0, etc.). However, this battle-tested impl is predicated on the tick base being
|
||||
// a multiple of the tick unit. So, to avoid changing key battle-tested logic, let's
|
||||
// do the following:
|
||||
// 1) Round the value to the nearest multiple of '2.5' (the tick size)
|
||||
// 2) Format the rounded value with normal tick factors (unit 5, base 10),
|
||||
// (ticks of the sort this method was designed to expect).
|
||||
var tuf = tick.tick_unit_frac<T>();
|
||||
var total_ticks = value / tuf;
|
||||
long total_ticks_l = NumericCastConverter<T, long>.convert(value / tuf);
|
||||
var rounded_total_ticks = NumericCastConverter<long, T>.convert(total_ticks_l);
|
||||
var rem = value - (rounded_total_ticks * tuf);
|
||||
var unit_rem = rem / tuf;
|
||||
Log.assert(unit_rem <= T.One && unit_rem >= T.Zero);
|
||||
// Check if unit_rem closer to T.One, or T.Zero. Round accordingly
|
||||
if (T.One - unit_rem <= unit_rem - T.Zero) {
|
||||
// round up
|
||||
rounded_total_ticks++;
|
||||
}
|
||||
var rounded_val = tuf * rounded_total_ticks;
|
||||
return _format_tick(new TickFactors(10, 5), rounded_val, settings);
|
||||
} catch (OverflowException ex) {
|
||||
Log.Ui.warn($"Arithmetic overflow exception in format_tick (tick:{tick}, value:{value}):{ex}");
|
||||
return "Overflow";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static T _round_tick<T>(T tick_unit_frac, T input) where T : IFloatingPointIeee754<T> =>
|
||||
|
||||
@@ -134,8 +134,20 @@ namespace bts.data.ticks {
|
||||
static TickFactors _inflate_to_base(TickFactors tick_factors, double new_base) =>
|
||||
new TickFactors(new_base, tick_factors.tick_unit * new_base / tick_factors.tick_base);
|
||||
|
||||
static bool _check_tick_size(double tick_size) =>
|
||||
tick_size > 0 && (tick_size <= 0.5 || MathUtils.is_int(tick_size));
|
||||
static bool _check_tick_size(double tick_size) {
|
||||
if (!tick_size.is_real_positive()) {
|
||||
return false;
|
||||
}
|
||||
if (tick_size <= 0.5 || tick_size.is_int()) {
|
||||
return true;
|
||||
}
|
||||
// Check if tick size represents quarters (i.e., `tick_size=0.25 * 10^c` for some int c).
|
||||
// Note: this check is designed specifically to support (non-perp) futures at Deribit
|
||||
if (Math.Log10(tick_size / 0.25).is_int()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct SpecKey : IEquatable<SpecKey> {
|
||||
public readonly uint denominator, display_digits;
|
||||
|
||||
@@ -209,6 +209,17 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public static decimal round_to_tick(decimal tick_size, decimal value) {
|
||||
if (tick_size == (decimal)2.5) {
|
||||
// This is a special case for [non-perp] futures at Deribit, which tick in 25/10
|
||||
// (unit/base). While this code looks harmless enough, and should work for all ticks in
|
||||
// theory, let's be extra safe and only apply the change to a specific case (when
|
||||
// tick_size == 2.5).
|
||||
// Note: Making the ticks code work for such a wide range of tick factors was no easy
|
||||
// task, and involved overcoming a plethora of obscure rounding errors along the way.
|
||||
var n_ticks = value / tick_size;
|
||||
var simple_round = tick_size * n_ticks;
|
||||
return simple_round;
|
||||
}
|
||||
decimal intpart = (long)value;
|
||||
decimal floatpart = value % 1;
|
||||
floatpart = ((int)(floatpart / tick_size)) * tick_size;
|
||||
@@ -293,6 +304,11 @@ namespace mbts.spark {
|
||||
if (!tf.low_tick.Equals(tf.high_tick) || !tf.is_valid() || tf.low_tick.is_integer())
|
||||
return null;
|
||||
var ticks_per_dollar = (uint)(tf.low_tick.tick_base / tf.low_tick.tick_unit);
|
||||
// Note: this check was introduced specifically to account for [non-perp] Futures at
|
||||
// Deribit, which use TickFactors 25/10 (e.g., 10.0, 12.5, 15.0, etc.).
|
||||
if (ticks_per_dollar == 0) {
|
||||
return null;
|
||||
}
|
||||
// if ticks_per_row is greater than ticks_per_dollar, round to a multiple of ticks_per_dollar
|
||||
if (ticks_per_row > ticks_per_dollar) {
|
||||
return (uint)(ticks_per_dollar * Math.Floor((double)(ticks_per_row / ticks_per_dollar)));
|
||||
|
||||
Reference in new issue
Block a user